事务的基本原理
- Spring事务的本质其实就是数据库对事务的支持。
- 事务是一系列的动作,一旦其中有一个动作出现错误,必须全部回滚,系统将事务中对数据库的所有已完成的操作全部撤销,回滚到事务开始的状态,避免出现由于数据不一致而导致的接下来一系列的错误。事务的出现是为了保证数据的完整性以及一致性,在目前企业级应用开发中,事务管理是必不可少的。
事务的四大特性(ACID)
- 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。操作要么全部完成,要么全部不完成。
- 一致性(Consistency):事务在完成时,所有的数据都必须保持一致状态。
- 隔离性(Isolation):当前事务不收并发事务执行的影响。在一个事务内部的操作对其他事务是不产生影响,需要事务隔离级别来指定隔离性。
- 持久性(Durability):一旦事务完成,数据库的改变必须是持久化的。
事务并发引起问题
- 事务的并发:在企业级应用中,多用户访问数据库是常见的场景。存在问题如下
- 脏读:一个事务读到另一个事务未提交的更新数据。
- 不可重复读:一个事务两次读同一行数据,可这两次读取到的数据不一样。
- 幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
- 丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖了。
- JDBC隔离级别:
- TRANSACTION_NONE JDBC:驱动不支持事务
- TRANSACTION_READ_UNCOMMITTED:允许脏读、不可重复读和幻读。
- TRANSACTION_READ_COMMITTED:禁止脏读,但允许不可重复读和幻读。
- TRANSACTION_REPEATABLE_READ:禁止脏读和不可重复读,单运行幻读。
- TRANSACTION_SERIALIZABLE:禁止脏读、不可重复读和幻读。
- 隔离级别越高,意味着数据库事务并发执行的性能越差,能处理的操作就越少。
Spring事务管理
- Spring事务管理的核心接口是Platform TransactionManager,事务管理器接口通过getTransaction方法根据指定的传播行为返回当前活动的事务或者创建一个新的事务。
Spring事务的传播属性
名称 | 值 | 解释 |
---|---|---|
PROPAGATION_REQUIRED | 0 | 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是Spring默认的事务的传播。 |
PROPAGATION_SUPPORTS | 1 | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 2 | 支持当前事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 3 | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 4 | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 5 | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 6 | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 |
Spring事务的隔离级别
名称 | 值 | 解释 |
---|---|---|
ISOLATION_DEFAULT | -1 | 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应 |
ISOLATION_READ_UNCOMMITTED | 1 | 这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。 |
ISOLATION_READ_COMMITTED | 2 | 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。 |
ISOLATION_REPEATABLE_READ | 4 | 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻读。 |
ISOLATION_SERIALIZABLE | 8 | 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。 |
配置事务管理器
-
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
-
Spring提供了两种事务管理的方式:编程式事务管理和声明式事务管理
编程式事务管理
-
通过
Platform TransactionManager
实现事务管理,同样Spring提供了模板类TransactionTemplate进行事务管理。 -
<!--配置事务管理的模板--> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> <!--定义事务隔离级别,-1表示使用数据库默认级别--> <property name="isolationLevelName" value="ISOLATION_DEFAULT"></property> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"></property> </bean>
-
在代码中使用:注入
TransactionTemplate
类,然后调用其execute
,重写doInTransactionWithoutResult
方法即可,如下-
@Resource private TransactionTemplate transactionTemplate; transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { try{ baseSevice.insert("INSERT INTO tbl_account VALUES (100);",false); } catch (Exception e){ //对于抛出Exception类型的异常且需要回滚时,需要捕获异常并通过调用status对象的setRollbackOnly()方法告知事务管理器当前事务需要回滚 status.setRollbackOnly(); e.printStackTrace(); } } });
-
-
优缺点:编程方式管理事务,极大灵活性,难维护。
声明式事务管理
-
声明式事务管理有两种常用的方式
- 基于tx和aop命名空间的xml配置文件
- 基于@Transactional注解
-
基于tx和aop命名空间的xml配置文件
-
配置文件:
<tx:advice id="advice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="insert" propagation="REQUIRED" read-only="false" rollback-for="Exception"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pointCut" expression="execution (* com.tmf.service.*.*(..))"/> <aop:advisor advice-ref="advice" pointcut-ref="pointCut"/> </aop:config>
-
-
基于@Transactional注解
-
这种方式是最简单,也是最为常用的,只需要在配置文件中开启对注解事务管理的支持。如下:
<!-- 声明式事务管理 配置事物的注解方式注入--> <tx:annotation-driven transaction-manager="transactionManager"/>
-
然后在需要事务管理的地方加上@Transcational注解:
@Transactional(rollbackFor=Exception.class)
-
rollbackFor属性指定出现Exception异常的时候回滚,遇到检查性的异常需要回滚,默认情况下非检查性异常,包括error也会自动回滚。
-