Spring容器下的数据库事务操作
文章目录
(一)什么情况下需要使用事务操作
- 当执行数据库操作的时候,第一个SQL语句执行正确,第二个语句错误的时候,需要把第一条执行的语句进行回滚操作!这个时候,就开始执行事务了。
JDBC自动提交事务,也就是当执行一个SQL语句的时候,就会主动把语句执行到数据库中
(二)在IOC容器中定义事务管理器
- 使用Advice(通知)事务管理器:DataSourceTransactionManager
<!-- TODO:增加事务管理器 -->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="c3p0DataSource"/>
</bean>
(三)执行事务的方式有两种:
执行事务的两种方式,主要还是针对AOP容器对增强类(Advice)的配置。其配置方式有两种:
- 基于命名空间的配置
<!-- TODO:配置事务管理器,基于命名空间,对数据库事务管理器 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- TODO:事务 -->
<tx:attributes>
<!-- TODO:事务管理的四个属性:传播属性(propagation),隔离级别(islation),回滚属性(rollback),readonly(只读优化),timeout(超处理) -->
<tx:method name="login" propagation="SUPPORTS" read-only="true"/>
<tx:method name="register" propagation="REQUIRED" isolation="READ_COMMITTED" rollback-for="java.lang.Exception" timeout="5000"/>
</tx:attributes>
</tx:advice>
<!-- TODO:对AOP容器中的操作数据库的Bean中的方法进行advice织入 -->
<aop:config>
<aop:pointcut id="pc" expression="execution(* service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
- 基于注解的配置
基于注解的事务配置,需要满足以下几个条件。一是处理事务方法的类必须是基于注解的类,且在IOC容器中;二是需要在IOC容器中增加事务管理器(.DataSourceTransactionManager);三是需要创建处理事务处理类和事务管理器之间的驱动!
- 在需要处理事务的方法上增加事务注解(代码示例)
@Service
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED,
rollbackFor = Exception.class)
public class UserLoginAndSignImpl implements UserLoginAndSign {
@Override
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public void login(String username, String password) {
}
@Override
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED,
rollbackFor = Exception.class,timeout = 5000)
public Integer sign(User user) {
return null;
}
}
- 在IOC容器中增加事务管理器和处理事务的类Bean的驱动
<tx:annotation-driven/>
(四)事务属性
事务的属性有五个:
1. 传播属性:propagtion
propagation:定义事务的边界,用来定义某个方法是否需要事务,常用的取值:
- REQUIRED 必须添加事务,如果当前没有事务,则创建一个新的事务,一般用于增删改操作
- SUPPORTS 可以没有事务,也可以有事务,如果当前有事务则运行,如果没有事务也可以运行。
2. 隔离级别属性:isolation
用来解决事务并发时会出现的一些问题。他有四种隔离级别:
- TRANSACTION_NONE: 指示事务不受支持的处理
- TRANSACTION_READ_COMMITTED: 已提交读,只读取已提交的,可以避免脏读,但仍有可能发生不可重复读,或虚读(幻读);
- TRANSACTION_READ_UNCOMMITTED:读取未提交的,这种情况下,三种问题都有可能发生,也就是可能会发生脏讯,不事重复读和虚读;
- TRANSACTION_REPEATABLE_READ:重复读,不会发生脏读和不可重复读,但是会发生虚读;
- TRANSACTION_SERIALIZABLE: 可序列化,避免脏读,不可重复读和幻读;相当于单并发;(这个
补充知识:多事务并发可能会现的三个问题:
- 脏读: 一个事务读取另一个事务没有提交的数据。主流数据库一般不会发生,如:MySQL,底层默认只读取提交的数据。(先读后提交)
- 不可重复读:一个事务已经读取数据,另一个事务在修改数据,可能导致使用的数据与数据库不同步。(先读后修改)
- 幻读: 一个事务读取数据,另外一个事务在增加、删除数据,导致的数据量与数据库不同步。(先读后修改,数理量不一致)
注:不可重复读和幻读是小概率事件,可能通过版本检查来解决,如Hibernate中悲观锁和乐观锁通过版本来检查,但太麻烦,而且效率低。所以,实际开发中不会使用隔离级别,大多情况下都使用的是定时任务+人工审核
3. 回滚条件属性:rollback
rollback属性在默认抛出RuntimeException时才会回滚
- rollbackFor=Exception.class: 表示发生该异常时回滚;
- noRollbackFor=Exception.class: 表示发生异常时不回滚
4. 只读优化:readOnly
readOnly:在该事务中只能读取,一般用于查询
5. 超时处理
timeout:配置事务的超时时间;
(五)四个事务特性:
- ACID原子性
- 一致性
- 隔离性
- 永久性
关于这四个特性,在MySQL 数据库学习中有体现!