1 spring支持的事务管理方式
spring支持两种事务管理方式,分别是编程式事务和声明式事务
1.1 编程式事务
spring内置了很多内置的事务管理器,比如DataSourceTransactionManager(JDBC、mybatis)、HibernateTransactionManager(Hibernate)、JtaTransactionManager(分布式)等,这些事务管理器都继承了AbstractPlatformTransactionManager抽象类,而AbstractPlatformTransactionManager类又继承了PlatformTransactionManager这个接口。PlatformTransactionManager这个接口有三个方法,分别是getTransaction(返回存在的事务或新建一个事务)、commit(提交事务)、rollback(回滚事务),编程式事务主要基于以上三个函数实现。看下面这个例子
@Autowired PlatformTransactionManager transactionManager;public void transactionTest (){ DefaultTransactionDefinition def = new DefaultTransactionDefinition(); //定义事务 def.setReadOnly(false); //读写 def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); //默认隔离级别 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //传播行为(有则加入,没有则新建) TransactionStatus status = transactionManager.getTransaction(def); //返回存在的事务或新建一个事务 try { //TODO something transactionManager.commit(status); //提交事务 } catch (Exception e) { transactionManager.rollback(status); //回滚事务 throw new InvoiceApplyException("异常失败"); } }
除了直接使用DefaultTransactionDefinition,还可以使用TransactionTemplate来简化事务处理,事务管理由模板进行定义。TransactionTemplate继承了DefaultTransactionDefinition类,通过调用模板类的参数类型为TransactionCallback或TransactionCallbackWithoutResult的execute方法来进行事务管理。看下面这个例子
@Autowired TransactionTemplate transactionTemplate;boolean result = transactionTemplate.execute(new TransactionCallback<Boolean>() { @Override public Boolean doInTransaction(TransactionStatus status) { try { // TODO something } catch (Exception e) { status.setRollbackOnly(); return false; } return true; } });
1.2 声明式事务
编程式事务需要手动进行事务管理,当业务量比较大时,每次都手动进行事务管理无疑是一场灾难。幸好spring提供了另一种事务管理方式——声明式事务管理。声明式事务管理本质上是基于AOP实现的,即对方法进行拦截,在方法执行之前创建或加入一个事务,方法执行完之后根据执行结果决定是要提交事务还是回滚事务。声明式事务不需要修改代码,属于无侵入式,其实现方式有两种,一种是使用spring的<tx:advice>和aop相关配置实现,另一种是使用@Transactional实现。
1、使用spring的<tx:advice>和aop相关配置
<!-- <tx:advice>用来定义事务,指定事务属性,其中“transaction-manager”属性指定事务管理器,并通过<tx:attributes>指定具体需要拦截的方法 <tx:method>拦截方法,其中参数有: name:方法名称,将匹配的方法注入事务管理,可用通配符 propagation:事务传播行为, isolation:事务隔离级别定义;默认为“DEFAULT” timeout:事务超时时间设置,单位为秒,默认-1,表示事务超时将依赖于底层事务系统; read-only:事务只读设置,默认为false,表示不是只读; rollback-for:需要触发回滚的异常定义,可定义多个,以“,”分割,默认任何RuntimeException都将导致事务回滚,而任何Checked Exception将不导致事务回滚; no-rollback-for:不被触发进行回滚的 Exception(s);可定义多个,以“,”分割; --> <tx:advice id="advice" transaction-manager="transactionManager"> <tx:attributes> <!-- 拦截insert开头的方法,事务传播行为为:REQUIRED:必须要有事务, 如果没有就在上下文创建一个 --> <tx:method name="insert*" propagation="REQUIRED" isolation="READ_COMMITTED" timeout="" read-only="false" no-rollback-for="" rollback-for=""/> <!-- 支持,如果有就有,没有就没有 --> <tx:method name="*" propagation="SUPPORTS"/> </tx:attributes> </tx:advice> <!-- 定义切入点,expression为切人点表达式 --> <aop:config> <aop:pointcut expression="execution(* com.*.*.service.*.*(..))" id="pointcut"/> <!--<aop:advisor>定义切入点,与通知,把tx与aop的配置关联,才是完整的声明事务配置 --> <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/> </aop:config>
2、使用@Transactional
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> //开启事务注解
需要说明的是@Transactional既可以用在类上,也可以用在接口和方法上,建议只在类上或方法上使用@Transactional。
2 事务特性
1、原子性(Atomicity):事务是不可分割的最小单元,事务内的操作要么全部成功,要么全部失败
2、一致性(Consistency):事务执行前后数据保持完整性,即事务操作过程中的中间状态对外部不可见。
3、隔离性(Isolation):并发执行的事务是相互隔离的,各事务之间不能相互干扰
4、持久性(Durability):事务执行完毕,数据就应该持久化到数据库
3 事务隔离级别
事务的隔离级别在TransactionDefinition类中定义,见下表
| 隔离级别 | 含义 | 备注 | 存在的问题 |
| 默认值 | 使用底层数据库的默认级别 | |
| 读未提交数据 | 可以读取事务未提交的数据 | 脏读、不可重复读、幻读 |
| 读已提交 | 只能读取已提交的事务的数据(sql server默认级别) | 不可重复读、幻读 |
| 可重复读 | 一个事务在整个过程中可以多次重复执行某个查询,每次返回的内容都一样 | 幻读 |
| 串行化 | 所有事务依次执行 |
脏读:一个事务读取 了另一个事务未提交的数据
不可重复读:一个事务中,多次查询结果不一样(记录内容发生了变化)
幻读:一个事务中,多次查询的结果,记录的个数不一样(记录增加或减少)
4 事务传播行为
事务的传播行为用来描述一个事务在另一个事务中嵌套运行时的表现方式,事务的传播行为也是在TransactionDefinition类中定义
| 传播行为 | 含义 | 备注 |
|---|---|---|
| 如果存在当前事务,则加入;如果不存在,则新建一个事务 | 嵌套事务和外围事务异常(即使嵌套事务的异常被外围事务捕获),都会导致事务回滚 |
| 如果存在当前事务,则加入;如果不存在,则以非事务方式运行 | 同上 |
| 如果存在当前事务,则加入;如果不存在,则抛异常 | 同上 |
| 新建一个事务,如果已经存在事务,则将原事务挂起 | 嵌套事务执行完之后可以先将数据持久化到数据库,在此之后外围事务或其他嵌套事务发生异常都不会导致已执行完的事务发生回滚 |
| 始终以非事务方式运行,如果存在事务,则将事务挂起 | 同PROPAGATION_REQUIRES_NEW |
| 始终以非事务方式运行,如果存在事务,则抛异常 | 同PROPAGATION_REQUIRES_NEW |
| 如果存在当前事务,则新建一个事务作为当前事务的嵌套事务运行;如果当前不存在事务,则运行方式跟PROPAGATION_REQUIRED一样(新建一个事务) | 嵌套事务或外围事务异常,都会导致事务回滚。但是对于嵌套事务发生的异常,如果外围事务捕获了这个异常,不影响其他事务持久化。 |
5 事务超时和只读属性
事务超时是指事务允许执行的最长时间,如果超时,事务将进行回滚。超时时间以秒为单位,默认为底层系统超时时间,如果底层系统未设置超时时间,则事务无超时时间
只读属性用于客户端不修改数据库的场景,只读属性可以优化事务,比如不使用部分数据库锁。需要注意的是只读事务里仍然可以修改数据库。

23万+

被折叠的 条评论
为什么被折叠?



