事务简介
- 事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性
- 事务就是一系列的动作,它们被当做一个单独的工作单元.这些动作要么全部完成,要么全部都不执行
- 事务的四个关键属性(ACID)
- 原子性(Atomicity):事务是一个原子操作,由一系列动作组成,事务的原子性确保动作要么全部完成要么全部不执行
- 一致性(Consistency):一旦所有事务动作完成,食物就被提交.数据和资源就处于一种满足业务规则的一致性状态中
- 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
- 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响.通常情况下,事务的结果被写到持久化存储器中
Spring中的事务管理
- Spring在不同的事务管理API之上定义了一个抽象层,而应用程序开发人员不必了解底层的事务管理API,就可以使用Spring的事务管理机制
- Spring既支持编程式事务管理,也支持声明式的事务管理
- 编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚.在编程式管理事务时,必须在每个事务操作中包含额外的事务管理代码
- 声明式事务管理:大多数情况下比编程式事务管理更好用,它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。事务管理作为一种横切关注点,可以通过AOP方法模块化,Spring通过Spring AOP框架支持声明式事务管理
Spring声明式事务的实现
配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="数据源id"></property>
</bean>
启用事务注解
<tx:annotation-driven transaction-manager="transactionManager"/>
在要启用的事务上添加事务注解(@Transactional)
事务的传播行为
- 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播.例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行
- 事务的传播行为可以由传播属性指定.Spring定义了7种传播行为
- REQUIRED:如果有事务正在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行(默认使用这种传播方式)
- REQUIRED_NEW:当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起。(被调用的多个事务间相互隔离)
- SUPPORTS:如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中
- NOT_SUPPORTS:当前的方法不应该运行在事务中,如果有运行的事务,将它挂起
- MANDATORY:当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常
- NEVER:当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
- NESTED:如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行
- 传播行为属性在@Transactional注解的propagation属性中定义
事务的隔离级别
并发事务所导致的问题
- 当同一个应用程序或者不同应用程序中的多个事务在同一个数据集上并发执行时,可能会出现许多意外的问题
- 并发事务所导致的问题可以分为下面三种类型:
- 脏读:对于两个事务T1和T2,T1读取了已经被T2更新但还没有被提交的字段。之后,若T2回滚,T1读取的内容就是临时且无效的
- 不可重复读:对于两个事务T1和T2,T1读取了一个字段,然后T2更新了该字段。之后,T1再次读取同一个字段,值就不同了
- 幻读:对于两个事务T1和T2,T1从一个表读取了一个字段,然后T2在该表中插入了一些新的行。之后,如果T1再次读取同一个表,就会多出几行
- 使用@Transactional注解的isolation属性指定事务隔离级别,最常用的取值为READ_COMMITTED
- 事务回滚:默认情况下,Spring的声明式事务对所有的运行时异常进行回滚,也可以通过对应的属性进行设置。如设置noRollbackFor={异常类类型},指定不回滚的异常类型
- 使用readOnly指定事务是否为只读,表示这个事务只读取数据但不更新数据,这样可以帮助数据库引擎优化事务
- 超时事务属性timeout:事务在强制回滚之前可以保持多久。这样可以防止长期运行的事务占用资源
使用XML文件配置事务
配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="数据源id"></property>
</bean>
配置事务属性
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="method1" propagation="REQUIRES_NEW"/>
<tx:method name="method2" read-only="true"/>
</tx:attributes>
</tx:advice>
配置事务切入点,以及把事务切入点和事务属性关联起来
<aop:config>
<aop:pointcut expression="execution(* com.vinsn.configuration.xml.xxService.*(..))" id="xxPointCut">
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut">
</aop:config>