Spring 框架的事务管理
1. Spring 框架的事务管理相关的类和API
PlateformTransactionManager 接口: 平台事务管理器(真正管理事务的类);TransactionDefinition 接口: 事务定义信息(事务的隔离级别,传播行为,超时,只读等);TransactionStatus 接口: 事务的状态;- 平台事务管理器真正管理事务对象,根据事务定义信息(
TransactionDefinition)进行事务管理,在管理事务
中产生的一些状态记录到TransactionStatus中;
1.1 PlateformTransactionManager 接口中实现类和常用的方法
- 接口的实现类
- 如果使用 Spring 框架的JDBC模板或者MyBatis框架,需要选择
DataSourceTransactionManager实现类; - 如果使用的是 Hibernate 框架,需要选择
HibernateTransactionManager实现类;
- 如果使用 Spring 框架的JDBC模板或者MyBatis框架,需要选择
- 该接口的常用方法
void commit(TransactionStatus status)TransactionStatus getTransaction(TransactionDefinition definition)void rollback(TransactionStatus status)
1.2 TransactionDefinition
事务隔离级别的常量
static int ISOLATION_DEFAULT: 采用数据库的默认隔离级别;static int ISOLATION_READ_UNCOMMITTEDstatic int ISOLATION_READ_COMMITTEDstatic int ISOLATION_REPEATABLE_READstatic int ISOLATION_SERIALIZABLE
事务的传播行为常量(一般使用默认值)
- 事务的传播行为:解决的是业务层之间的方法调用!
- 保证 A,B 在同一个事务中:
PROPAGATION_REQUIRED(默认值): A中有事务,使用A中的事务;如果没有,B会开启一个新的事务,
将A包含进来(保证A,B在同一个事务中);PROPAGATION_SUPPORTS: A中有事务,使用A中的事务;如果A中没有事务,那么B也不使用事务;PROPAGATION_MANDATORY: A中有事务,使用A中的事务; 如果A中没有事务,抛出异常;
- 保证 A,B 没有在同一个事务中:
PROPAGATION_REQUIRES_NEW: A中有事务,将A中的事务挂起,B创建一个新的事务,
(保证A,B不在同一个事务中);PROPAGATION_NOT_SUPPORTED: A中有事务,将A中的事务挂起;PROPAGATION_NEVER: A中有事务,抛出异常;
PROPAGATION_NESTED: 嵌套事务,当 A 执行之后,就会在这个位置设置一个保存点,如果B没有问题,
执行通过;如果B出现异常,根据需求回滚(可以回滚到保存点或最初始的状态);

2. 搭建事务管理转账案例的环境
2.1 导入 jar 包
- Spring 框架的基本开发包(6个);
- Spring 的传统AOP的开发包
spring-aop-4.3.10.RELEASEorg.aopalliance-1.10.0(在 Spring 依赖包中)
- aspectJ 的开发包
org.aspectj.weave-1.6.8.RELEASE.jar(在 Spring 依赖包中)spring-aspects-4.3.10.RELEASE.jar
- JDBC 模板所需 jar 包
mysql-connector-java.jar: MySql 驱动包;Spring-jdbc.jar;Spring-tx.jar: Spring 事务包;
- c3p0 的 jar 包:
com.mchange.v2.c3p0-0.9.1.2.jar
2.2 创建对应的包结构和类
com.itheima.demoAccountServiceAccountServiceImplAccountDaoAccountDaoImpl
// AccountDao.java
public class AccountDao {
// 扣钱
public void outMoney(String out, double money);
// 加钱
public void inMoney(String in, double money);
}
// AccountService.java
public class AccountService{
public void pay(String out,String in, double money);
}
// AccountDaoImpl.java
// 第一种方式, 使用 jdbc 模板类
public class AccountDaoImpl implements AccountDao{
// 使用 jdbc 模板操作数据库
// 在配置文件中注入 jdbcTemplate 对象
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
// 扣钱
public void outMoney(String out, double money){
jdbcTemplate.update(sql,args);
}
// 加钱
public void inMoney(String out, double money){
jdbcTemplate.update(sql,args);
}
}
// 第二种方式, 继承 JdbcDaoSupport类, 该类中包含 jdbcTemplate,并且提供了 set方法
// applicationContext.xml 中仍需要注入 jdbcTemplate 对象
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
// 扣钱
public void outMoney(String out, double money){
this.getJdbcTemplate().update(sql,args);
}
// 加钱
public void inMoney(String in, double money){
this.getJdbcTemplate().update(sql,args);
}
}
// 第三种方式: applicationContext.xml 中无需注入 jdtcTemplate 对象
// 只需要注入连接池对象,
// JdbcDaoSupport 类内部,在 jdbcTemplate 对象为 null 时, 根据连接池创建 jdbcTemplate 对象
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
// 扣钱
public void outMoney(String out, double money){
this.getJdbcTemplate().update("UPDATE t_account SET"
+"money = money - ? WHERE name = ?",money,out);
}
// 加钱
public void inMoney(String in, double money){
this.getJdbcTemplate().update("UPDATE t_account SET"
+"money = money - ? WHERE name = ?",money,in);
}
}
// AccountServiceImpl.java
public class AccountServiceImpl implements AccountService{
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao){
this.accountDao = accountDao;
}
// 实现转账功能
public void pay(String out, String in, double money){
accountDao.outMoney(out,money);
accountDao.inMoney(in,money);
}
}
// 测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo{
@Resource(name="accountService")
private AccountServiceImpl accountService;
@Test
public void fun(){
// 测试支付方法
accountService.pay("张三","李四",100);
}
}
2.3 applicationContext.xml
<!-- 管理c3p0 连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb1"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- 管理JDBC的模板类 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" value="dataSource"/>
</bean>
<!-- 配置业务层和持久层 -->
<bean id="accountService" class="com.itheima.demo.AccountServiceImpl">
<property name="accountDao" value="accountDao"/>
</bean>
<!-- 第一种和第二种方式, 需要注入 jdbcTemplate 对象 -->
<bean id="accountDao" class="com.itheima.demo.AccountDaoImpl">
<property name="jdbcTemplate" value="jdbcTemplate"/>
</bean>
<!-- 第三种方式, 只需要注入连接池 -->
<bean id="accountDao" class="com.itheima.demo.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
2.4 Spring 框架事务管理的分类
- Spring 的编程式事务管理(不推荐使用)
- 通过手动编写代码的方式完成事务的管理;
- Spring 的声明式事务管理(底层采用AOP的技术)
- 通过一段配置的方式完成事务的管理;
2.4.1 编程式的事务管理
- 手动编程的方式来管理事务,需要使用
TransactonTemplate模板类;
// 具体步骤
// 1. 配置一个事务管理器
// Spring 框架使用 PlatFormTransactionManager 接口来管理事务,需要使用到它的实现类
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
// 底层操作事务的是 connection, 该对象存放在连接池
// 事务管理器管理事务,需要从连接池中获取 connection 对象
<property name="dataSource" ref="dataSource"/>
</bean>
// 2. 配置事务管理的模板
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
// 3. 在需要进行事务管理的类中,注入事务管理的模板
// 备注: 事务需要在业务层开启
<bean id="accountService" class="com.itheima.demo.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
// 4. 在业务层使用模板管理事务
public void AccountServiceImpl implements AccountService{
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao){
this.accountDao = accountDao;
}
// 注入事务模板对象
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate){
this.transactionTemplate = transactionTemplate;
}
// 实现转账功能
public void pay(final String out, final String in, final double money){
transactionTemplate.execute(new TransactionCallbackWithoutResult(){
protected void doInTransactionWithoutResult(TransactionStatus status){
// 扣钱
accountDao.outMoney(out,money);
// 异常
int a = 10 / 0;
// 加钱
accountDao.inMoney(in,money);
}
});
}
}
2.4.2 声明式事务管理
- 声明式事务管理:即通过配置文件来完成事务管理(AOP 思想)
- 基于AspectJ的XML方式;(重点掌握)
- 基于AspectJ的注解方式;(重点掌握)
基于AspectJ的XML方式
// applicationContext.xml
// 1. 配置一个事务管理器
// Spring 框架使用 PlatFormTransactionManager 接口来管理事务,需要使用到它的实现类
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
// 底层操作事务的是 connection, 该对象存放在连接池
// 事务管理器管理事务,需要从连接池中获取 connection 对象
<property name="dataSource" ref="dataSource"/>
</bean>
// 2. 配置事务增强(通知)
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
可以配置多个 method;
name : 绑定事务的方法名,可以使用通配符;
propagation: 传播行为;
isolation : 隔离级别;
read-only : 缓存是否只读;
timeout : 超时信息;
rollback-for: 发生哪些异常信息回滚;
no-rollback-for: 发生哪些异常,不回滚;
-->
<tx:method name="pay" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
// 3. 配置 AOP 切面
// 备注: 如果是自定义的切面,使用<aop:aspect>标签, 如果是系统自带的,使用<aop:advisor>标签
<aop:config>
<aop:advisor advice-ref="myAdvice"
pointcut="execution(public * com.itheima.demo.AccountServiceImpl.pay(..))"/>
</aop:config>
// 4. 持久层配置
<bean id="accountService" class="com.itheima.demo.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
基于AspectJ的注解方式(重点掌握,这是最简单的方式)
// 1. 配置事务管理器
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
// 2. 开启注解事务
<tx:annotation-driven transaction-manager="transactionManager"/>
// 3. 在业务层上添加一个注解: @Transactional
// AccountServiceImpl.java
// 如果在这个类上添加注解, 类中的所有方法全部都有事务
@Transactional
public class AccountServiceImpl implements AccountService{
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao){
this.accountDao = accountDao;
}
// 实现转账功能
// 如果在方法上添加,只有该方法有事务
@Transactional
public void pay(String out, String in, double money){
accountDao.outMoney(out,money);
accountDao.inMoney(in,money);
}
}
参考资料
Spring 框架的事务管理的更多相关文章
- Spring框架之事务管理
Spring框架之事务管理 一.事务的作用 将若干的数据库操作作为一个整体控制,一起成功或一起失败. 原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生. 一致性:指事务前后 ...
- Spring框架的事务管理之编程式的事务管理(了解)
1. 说明:Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,所以手动编程的方式来管理事务,只需要使用该模板类即可!!2.手动编程方式的具体步骤如下: 1.步骤 ...
- Spring框架的事务管理相关的类和API
1. PlatformTransactionManager接口 -- 平台事务管理器.(真正管理事务的类).该接口有具体的实现类,根据不同的持久层框架,需要选择不同的实现类! 2. Transacti ...
- Spring框架的事务管理之基于AspectJ的XML方式(重点掌握)
1. 步骤一:恢复转账开发环境(转账开发环境见“https://www.cnblogs.com/wyhluckdog/p/10137283.html”) 2.步骤二:引入AOP的开发包3.步骤三:引入 ...
- Spring框架的事务管理的分类
1. Spring的事务管理的分类 1. Spring的编程式事务管理(不推荐使用) * 通过手动编写代码的方式完成事务的管理(不推荐) 2. Spring的声明式事务管理(底层采用AOP的技术) * ...
- (三)Spring框架之事务管理
一.编程式事务管理 Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,事务管理器接口PlatformT ...
- Spring框架的事务管理有哪些优点?
它为不同的事务API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一个不变的编程模式. 它为编程式事务管理提供了一套简单的API而不是一些复杂的事务API如 它支持声明式事务管理 ...
- Spring 框架的事务管理有哪些优点?
它为不同的事务 API 如 JTA,JDBC,Hibernate,JPA 和 JDO,提供 一个不变的编程模式. 它为编程式事务管理提供了一套简单的 API 而不是一些复杂的事务 API 它支持声明式 ...
- Spring框架的事务管理之基于AspectJ的注解方式(重点掌握,最简单的方式)
1. 步骤一:恢复转账的开发环境(具体开发环境实现见:https://www.cnblogs.com/wyhluckdog/p/10137283.html)2. 步骤二:applicationCont ...
随机推荐
- HTTP基本认证(Basic Authentication)的JAVA实例代码
大家在登录网站的时候,大部分时候是通过一个表单提交登录信息. 但是有时候浏览器会弹出一个登录验证的对话框,如下图,这就是使用HTTP基本认证. 下面来看看一看这个认证的工作过程: 第一步: 客户端发送 ...
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown character set: 'utf8mb4'
排除 1.mysql 是utf8 2.连接url加了useUnicode=true&&characterEncoding=utf8 3.项目也没有用到utf8mb4 由于是mysql驱 ...
- Android实例-IdHTTP下载(并实现自动安装)(XE10+小米2)
相关资料: 1.群号 383675978 2.运行时提示"connection closed gracefully"错误原因与解决 http://www.delphifans.co ...
- HTML5坦克大战(1)绘制坦克
坦克尺寸如下: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head&g ...
- 您的位置:首页 » IOS » iOS中全局悬浮按钮,类似IPhone中的AssistiveTouch iOS中全局悬浮按钮,类似IPhone中的AssistiveTouch
原文地址:http://blog.5ibc.net/p/86562.html 前提:当时看到别人写过这个类似AssistiveTouch的demo,但是有问题,第一改变不了位置.第二切换页面后无法使用 ...
- CCRenderTexture画点出现十字架"歪解"
在泰然论坛发个了帖子,没有人解答,内容如下: 遇到奇葩问题了,cocos2dx 2.2 CCRenderTexture* tex=CCRenderTexture::create(, ); tex-&g ...
- Unix系统编程()open,read,write和lseek的综合练习
需求:程序的第一个命令行参数为将要打开的文件名称,余下的参数则指定了文件上执行的输入输出操作.每个表示操作的参数都以一个字母开头,紧跟以相关值(中间无空格分隔). soffet:从文件开始检索到off ...
- Azkaban安装配置
描述: azkaban主要用于离线计算任务的调度 说明: 此处Azkaban选择版本为:3.52.0,部署方式为Cluster模式,即支持多Executor计算节点,目前默认安装方式选择在同一台机器上 ...
- 6:7 题一起MySQL数据库分库备份
企业Shell面试题6:MySQL数据库分表备份 请实现对MySQL数据库进行分表备份,用脚本实现. 解答: [root@db01 scripts]# cat fenbiao.sh #!/bin/ba ...
- 微信小程序5 - 数据驱动界面
微信小程序不可以使用js直接控制界面元素.而是通过改变 this.data中的属性,同步到界面 这个问题可以克服,带来的就是和H5不一样的编码方式.JS中更多的是改变数据的逻辑,而不是获取某个View ...