ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] # 简介 ## PlatformTransactionManager 此接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法 ![](https://img.kancloud.cn/38/1a/381a108a882c99d44e69e6f55da2b325_659x317.png) 我们在开发中都是使用它的实现类 真正管理事务的对象 ~~~ org.springframework.jdbc.datasource.DataSourceTransactionManager 使用 Spring JDBC 或 iBatis 进行持久化数据时使用 org.springframework.orm.hibernate5.HibernateTransactionManager 使用 Hibernate 版本进行持久化数据时使用 ~~~ ## TransactionDefinition 它是事务的定义信息对象,里面有如下方法 ![](https://img.kancloud.cn/ee/d1/eed1acb278528c71d3e64b1a3edf2432_503x380.png) ## 事务的隔离级别 ![](https://img.kancloud.cn/0e/38/0e3895bf6928765886d0fdda6efe1c28_738x429.png) ## 事务传播行为 * REQUIRED:如果当前没 有事务,就 新建一个 事务,如果已经存在 一个事务 中,加入 到这个事务 中。一般 的选 择(默认值) * SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务) * MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常 * REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。 * `NOT_SUPPORTED`:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起 * NEVER:以非事务方式运行,如果当前存在事务,抛出异常 * NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。 ## 超时时间 默认值是-1,没有超时限制。 如果有,以秒为单位进行设置。 ## 是否是只读事务 建议查询时设置为只读 ## TransactionStatus 此接口提供的是事务具体的运行状态,方法介绍如下图 ![](https://img.kancloud.cn/a1/de/a1de5aafdc547fae518b17f2d4700181_661x380.png) # xml 转账代码要对他加事务 ~~~ public void transfer(String sourceName, String targeName, Float money) { //1.根据名称查询两个账户 Account source = accountDao.findAccountByName(sourceName); Account target = accountDao.findAccountByName(targeName); //更新两个账户 target.setMoney(target.getMoney() + money); source.setMoney(source.getMoney() - money); accountDao.updateAccount(source); //int i = 1 / 0; accountDao.updateAccount(target); } ~~~ xml中配置 ~~~ <!-- 配置数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:///app"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> <!-- spring中基于xml的声明式事务控制配置步骤 1. 配置事务管理器 2. 配置事务的通知, 要导入约束 使用tx:advice配置事务通知 属性: id 事务通知唯一标识 transaction-manager: 给事务通知提供一个事务管理器引用 3. 配置aop中通用切入点表达式 4. 建立事务通知和切入点表达式的对应关系 5. 配置事务的属性 是在事务通知的tx:advice标签的内部 --> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事务通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 配置事务的属性 isolation: 指定事务的隔离级别,默认值是DEFAULT,表示用数据库的 no-rollback-for:指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚.没有默认值表示任何异常都回滚 propagation: 指定事务的传播新闻,默认值是REQUIRED,表示一定会有事务.查询可以选择SUPPORTS read-only: 指定事务是否只读,只有查询方法才能设置true,默认false表示读写 rollback-for: 指定一个异常,当产生这个异常事务将回滚,其他异常事务不回滚.没有默认值表示任何异常都回滚 timeout: 指定事务的超时时间 --> <tx:attributes> <tx:method name="*" propagation="REQUIRED" read-only="false" /> <!-- 下面优先级比上面高,find*方法 --> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <!-- 配置aop --> <aop:config> <!-- 切入点表达式 --> <aop:pointcut id="pt1" expression="execution(* com.jdxia.service.*.*(..))" /> <!-- 建立切入点表达式和事务的关系 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1" /> </aop:config> ~~~ # aop 类上加这个 ~~~ @Service("accountServiceImpl") //类上加上这个 @Transactional(propagation = Propagation.SUPPORTS, readOnly = true) public class AccountServiceImpl implements IAccountService { ~~~ 方法上加这个(如果和类不同的话) ~~~ //需要单独配置事务 @Transactional(propagation = Propagation.REQUIRED, readOnly = false) @Override public void transfer(String sourceName, String targeName, Float money) { //1.根据名称查询两个账户 Account source = accountDao.findAccountByName(sourceName); Account target = accountDao.findAccountByName(targeName); //2.修改两个账户的金额 source.setMoney(source.getMoney()-money);//转出账户减钱 target.setMoney(target.getMoney() + money);//转入账户加钱 //3.更新两个账户 source.setMoney(source.getMoney() - money); accountDao.updateAccount(source); //int i = 1 / 0; accountDao.updateAccount(target); } ~~~ ~~~ /** * @Transactional 可以标注的位置: * 类上 : 对类中的每个方法都起作用 * 方法上 : 只对当前的方法起作用 * 如果类上和方法上都加了该注解,方法上的优先. * * @Transactional 注解的属性: * * 1. propagation 事务的传播行为 事务是可以进行传播的, 一个事务方法调用另一个事务方法时,会把当前方法的事务传递给被调用的方法. * 被调用的方法可以决定如何使用事务. * REQUIRED: 默认值, 使用调用者的事务. * REQUIRES_NEW: 将调用者的事务挂起,开启新的事务来使用. * * 2. isolation 事务的隔离级别 * * 读未提交 READ_UNCOMMITTED 1 脏读 * 读已提交 READ_COMMITTED 2 不可重复读 * 可重复读 REPEATABLE_READ 4 幻读 * 串行化 SERIALIZABLE 8 效率低 * * * 3. timeout 事务的超时设置 事务在强制回滚之前可以占用的时间. * * 4. readOnly 事务的只读设置 可以帮助数据库引擎优化事务 * * 5. 事务的回滚与不回滚的设置 默认情况下,Spring会对所有的运行时异常进行回滚. * rollbackFor * rollbackForClassName * noRollbackFor * noRollbackForClassName */ @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED, timeout=3,readOnly=false ,noRollbackFor= {UserAccountException.class}) ~~~ xml中 ~~~ <!-- aop扫描包 --> <context:component-scan base-package="com.jdxia" /> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- spring中基于注解的声明式事务控制配置步骤 1. 配置事务管理器 2. 开启spring对注解事务的支持 3. 在需要事务支持地方使用transactional注解 --> <tx:annotation-driven transaction-manager="transactionManager" /> ~~~ # 编程式事务 直接在 ~~~ transactionTemplate.execute(new TransactionCallback<Object>() { ~~~ 这里面写就行 ~~~ public void transfer(String sourceName, String targetName, Float money) { transactionTemplate.execute(new TransactionCallback<Object>() { @Override public Object doInTransaction(TransactionStatus status) { System.out.println("transfer...."); //2.1根据名称查询转出账户 Account source = accountDao.findAccountByName(sourceName); //2.2根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //2.3转出账户减钱 source.setMoney(source.getMoney()-money); //2.4转入账户加钱 target.setMoney(target.getMoney()+money); //2.5更新转出账户 accountDao.updateAccount(source); // int i=1/0; //2.6更新转入账户 accountDao.updateAccount(target); return null; } }); } ~~~