什么是事物?
事物指的是逻辑上的一组操作,这组操作要么全部成功?要么全部失败。
事物的特性
- 原子性:事物是一个不可分割的单位,事物中的操作要么都发生,要么都不发生
- 一致性:事物前后数据的完整性必须保持一致
- 隔离性:多个用户并发访问数据库的时候,一个用户的事物不能被另一个干扰
- 持久性:一个事物一旦被提交,他对数据库中的数据改变就是永久的,即使数据库发生故障也不应该对其有任何影响
Spring事务管理
3个接口
PlatformTransactionManager
常用的接口实现类:
- DataSourceTransaction
- HibernateTransactionManager
TransactionDefinition
如果不考虑事物的隔离性问题,将会引发安全性问题:
脏读、不可重复读、幻读
- 脏读:一个事物读取了另外一个事物改写尚未提交的数据,如果事物被回滚,则读到的数据是无效的
- 不可重复读:同一个事物里面读到另一个事物已经提交的更新的数据而导致这个事物中多次查询结果不一致
- 幻读:一个事物读取了几行记录后,另外一个事物插入一些记录,幻读就发生了。在后来的查询中就会发现有些原来没有的记录
事物隔离级别
- DEFAULT:使用后端数据库默认的隔离级别(Spring中的选择项)
- READ_UNCOMMITED:允许你读取还没提交的改变的数据。可能导致脏读、幻读、不可重复读
- READ_COMMITED:允许再并发事物已经提交后读取。可防止脏读,但幻读和不可重复读可能发生
- REPEATABLE_READ:对相同 字段的多次读取时一致的,除非数据被事物本身改变。可防止脏读、不可重复读。但幻读仍可能发生
- SERIALIZABLE:完全服从ACID的级别,确保不发生脏读、幻读和不可重复读。这在所有的隔离级别中是最慢的。它是典型的通过完全锁定在事物中涉及的数据表完成
MySQL中默认采用REPEATABLE_READ隔离个别
Oracle默认采用READ_COMMITED隔离级别
事物的传播行为:
解决业务方法相互调用产生的事物应该如何传递的行为
- PROPAGATION_REQUIRED*:支持当前事物,不存在则创建新事物
- PROPAGATION_SUPPORTS:支持当前事物,如果不存在就不使用事物
- PROPAGATION_MANDATORY:支持当前事物,如果不存在就显示异常
- PROPAGATION_REQUIRES_NEW* :如果有事务存在就挂起当前事物,创建一个新的事物
- PROPAGATION_NOT_SUPPORTED :以非事物方式运行,如果有事务 就挂起当前事物
- PROPAGATION_NEVER :以非事物方式运行,如果有事物存在就抛出异常
- PROPAGATION_NESTED* :如果有事务存在,则嵌套事物执行
TransactionStatus
提供一系列接口
使用XML配置声明式事务
- 推荐使用(代码侵入性最小)
- spring的声明式事物是AOP实现的
- 业务方法执行前开启事物,结束后关闭事物
prop格式:
- PROPAGATION:传播行为
- ISOLATION:隔离级别
- readOnly:只读
- -Exception:发生这些异常回滚事物
- +Exception:发生这些异常提交事务
基于AspectJ
- propagation:传播行为
- isolation:隔离级别
- read-only:只读
- rollback-for:发生这些异常回滚事物
- no-rollback-for:发生这些异常提交事务
- timeout:过期信息
总结
Spring将事物管理分成两类:
- 编程式事务管理:
- 手动编写代码进行事务管理
- 声明式事物管理
- 基于TransactionProxyFactoryBean(很少使用) 需要为每个进行事物管理的类配置一个TransactionProxyFactoryBean
- 基于AspectJ的xml方式:一旦配置好后不需要添加任何东西
- 基于注解方式配置简单,需要在业务层添加一个@Transactional
原始的XML方式:
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置业务层的代理 -->
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置目标对象 -->
<property name="target" ref="accountService" />
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务的属性 -->
<property name="transactionAttributes">
<props>
<!--
prop的格式:
* PROPAGATION :事务的传播行为
* ISOTATION :事务的隔离级别
* readOnly :只读
* -EXCEPTION :发生哪些异常回滚事务
* +EXCEPTION :发生哪些异常不回滚事务
-->
<prop key="transfer">PROPAGATION_REQUIRED</prop>
<!-- <prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop> -->
<!-- <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> -->
</props>
</property>
</bean>
<!-- ==================================3.使用XML配置声明式的事务管理,基于tx/aop=============================================== -->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置事务的通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
propagation :事务传播行为
isolation :事务的隔离级别
read-only :只读
rollback-for:发生哪些异常回滚
no-rollback-for :发生哪些异常不回滚
timeout :过期信息
-->
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
<!-- ==================================4.使用注解配置声明式事务============================================ -->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
/**@Transactional
*propagation
*isolation
*readOnly
*rollbackFor
*noRollbackFor
*rollbackForClassName */
@Transactional
public class AccountServiceImpl implements AccountService{
}