在spring中,事物管理一般分为两类,编程式事务管理和声明式事务管理。 编程式事务管理,一般我们使用TransactionTemplate来实现。
声明式事物管理本质上是spring AOP的实现,对目标方法进行拦截,在目标方法之前加入事务,在执行完目标方法之后根据执行情况,进行回滚或者提交两种操作。
下面分别介绍两种方式的实现
首先是xml配置
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>这里配置事务管理器的时候spring为不同的orm框架实现了不同的platformTransactionManager接口实现
事务orm框架org.springframework.jdbc.datasource.DataSourceTransactionspring jdbc和ibatisorg.springframework.orm.hibernate3.Hibernate.TransactionManagerhibernate3.0org.springframework.orm.jpa.JpaTransactionManagerspring data JPAorg.springframework.jdo.JdoTransactionManager持久化机制Jdoorg.springframework.transaction.jta.JtaTransactionManager使用JTA常用的主要是上面两种
使用时
this.getTransactionTemplate().execute(new TransactionCallback()){ public Object doInTransaction(TransactionStatus arg0){ 操作数据库语句a 操作数据库语句b } }
它主要是基于AOP实现,在使用时首先配置xml
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <tx:annotation-driven transaction-manager="transactionManager">这要我们就可以直接在代码中使用@Transactional注解来开启事务
@Transactional public void deleteUser(Long userId) throws VaException { //操作数据库语句a //操作数据库语句b }此时如果中途发生异常,已执行的操作会回滚。
springboot使用事务,只需要在类或者方法上标注@Transactional即可。springboot会根据我们使用的orm框架自动配置合适的事务管理器。
但是需要注意的是springboot中使用@Transactional可能失效的问题: 1.Spring 只会回滚运行时、未检查异常(继承自 RuntimeException 的异常)或者 Error和未被catch的异常 这是由于spring底层实现transactionTemplate决定的看源码
public <T> T execute(TransactionCallback<T> action) throws TransactionException { Assert.state(this.transactionManager != null, "No PlatformTransactionManager set"); if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action); } else { TransactionStatus status = this.transactionManager.getTransaction(this); Object result; try { result = action.doInTransaction(status); } catch (Error | RuntimeException var5) { //错误和运行期异常 this.rollbackOnException(status, var5); throw var5; } catch (Throwable var6) { this.rollbackOnException(status, var6); throw new UndeclaredThrowableException(var6, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); return result; } }2.@Transactional 注解只能应用到 public 方法才有效
所以当你有checked类型的异常时,你可以通过设置属性来是注解生效(可以是一个或者多个) 如@Transactional(rollbackFor=RuntimeException.class) 还有如下一些常用参数: readOnly: 设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false
noRollbackFor:设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚
propagation:设置事务的传播行为
isolation:设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可。
timeout :事务的超时时间,默认值为-1(表示不限时间)。如果超过该时间限制但事务还没有完成,则自动回滚事务,单位为second
因为spring使用AOP技术动态代理来实现@Transactional,但是动态代理有两种,spring如何选择?如果一个类有顶层接口,则默认使用jdk的动态代理来代理,如果直接是一个类,则使用cglib动态代理。
@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE):串行化
TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。 TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行; 如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。