事务管理>>>>Spring
1. 事务的基本要素(ACID)
1.1 原子性(Atomicity)
事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
1.2 一致性(Consistency)
事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
1.3 隔离性(Isolation)
同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱结束前,B不能向这张卡转账。
1.4 持久性(Durability)
事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
2. 事务并发问题
2.1 脏读(Dirty reads)
事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
2.2 不可重复读(Nonrepeatable read)
事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
2.3 幻读(Phantom read)
用户A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是用户B就在这个时候插入了一条具体分数的记录,当修改A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。
3. 事务的隔离级别
3.1 读取未提交(ISOLATION_READ_UNCOMMITTED)
读取未提交:事务中的修改,即使没有提交,其他事务也可以看得到,会导致脏读,不可重复读,幻读。
3.2 读取已提交((ISOLATION_READ_COMMITTED)
读取已提交(Oracle数据库默认隔离级别):一个事务不会读到其它并行事务已修改但未提交的数据。避免了脏读,但会导致不可重复读,幻读。
3.3 可重复读取(ISOLATION_REPEATABLE_READ)
可重复读取(Mysql数据库默认的隔离级别):一个事务不会读到其它并行事务已修改且已提交的数据,(只有当该事务提交之后才会看到其他事务提交的修改)。避免了脏读,不可重复读,但会导致幻读。
3.4 可串行化(ISOLATION_SERIALIZABLE)
可串行化:事务串行执行,一个时刻只能有一个事务被执行。避免了脏读,不可重复读,幻读。
4. Spring事务控制
- JavaEE 体系进行分层开发,事务处理位于业务层,Spring提供了分层设计业务层的事务处理解决方案。
- Spring 框架为我们提供了一组事务控制的接口,这组接口在spring-tx-5.0.2.RELEASE.jar 中。
- Spring 的事务控制都是基于AOP的,它既可以使用配置的方式实现,也可以使用编程的方式实现。推荐使用配置方式实现。
4.1. Spring中事务控制的API
Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。通过事务管理器PlatformTransactionManager,Spring为各个平台如JDBC、Hibernate等提供了对应的事务管理器,但是具体的实现依赖各自平台的事务实现。
PlatformTransactionManager接口: 是Spring提供的事务管理器
它提供了操作事务的以下方法:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
- TransactionStatus getTransaction(TransactionDefinition definition) : 获得事务状态信息。
- void commit(TransactionStatus status) : 提交事务。
- void rollback(TransactionStatus status) : 回滚事务。
在实际开发中我们使用的是PlatformTransactionManager接口的实现类:
- org.springframework.jdbc.datasource.DataSourceTransactionManager 使用SpringJDBC或iBatis进行持久化数据时使用。
- org.springframework.orm.hibernate5.HibernateTransactionManager 使用Hibernate版本进行持久化数据时使用。
TransactionDefinition: 事务定义信息对象
它提供查询事务定义的方法:
- String getName() : 获取事务对象名称。
- int getIsolationLevel() : 获取事务隔离级别,设置两个事务之间的数据可见性。
从这里我们可以看到具体的事务管理机制对Spring来说是透明的,所以Spring事务管理的一个优点就是为不同的事务API提供一致的编程模型,如JTA、JDBC、Hibernate等。
4.2. spring事务定义及状态描述
从事务管理器PlatformTransactionManager中可以看出,spring完成事务管理还需2个关键元素:事务定义TransactionDefinition及事务状态TransactionStatus描述。
public interface TransactionDefinition {
int getPropagationBehavior(); //传播行为,默认PROPAGATION_REQUIRED
int getIsolationLevel(); //隔离级别,默认数据库默认级别,如mysql为可重复读
int getTimeout();
boolean isReadOnly(); //是否只读,查询操作可以设置为true
String getName();
}
4.2.1.事务传播行为
有两个含有事务的方法A和B,B调用A时,A是启用新事务还是延续B的事务,这便是事务传播行为,Spring提供了7种事务传播行为:
- PROPAGATION_REQUIRED:当前方法必须运行在事务中,如果存在当前事务则加入当前事务,否则开启新事务,spring 默认行为。
- PROPAGATION_SUPPORTS:当前方法不需要事务上下文,如果存在当前事务则加入当前事务,否则裸奔。
- PROPAGATION_MANDATORY:方法必须在事务中运行,当前事务不存在则报错。
- PROPAGATION_REQUIRES_NEW:方法运行在自己的新事务中。
- PROPAGATION_NOT_SUPPORTED
- PROPAGATION_NEVER
- PROPAGATION_NESTED:已存在当前事务则运行在嵌套事务中,否则开启新事务,涉及savepoint。
4.2.2.事务状态描述
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction(); //是否新事务
boolean hasSavepoint(); //是否有恢复点
void setRollbackOnly();
boolean isRollbackOnly();
void flush(); //Flush the underlying session to the datastore, if applicable: for example, all affected Hibernate/JPA sessions.
boolean isCompleted();
}
可以看出这个接口描述的是一些处理事务提供简单的控制事务执行和查询事务状态的方法,事务管理器在回滚或提交时,需要对应的TransactionStatus。
5. Spring事务的实现方式
编程式事务和声明式事务是spring的两种事务实现方式:
- 编程式事务可以直接通过PlatformTransactionManager来实现,也可以通过TransactionTemplate简单实现;
- 声明式事务则可以通过xml配置或@Transactional注解方式实现。
5.1. 编程式事务实现
spring 配置文件 jdbc-tx.xml
5.2. 声明式事务实现
5.2.1. xml配置方式声明事务
spring配置文件:jdbc-tx-xml.xml,区别与jdbc-tx.xml增加aop事务拦截
5.2.2. 注解方式声明事务
spring配置文件:jdbc-tx-anotation.xml,区别于jdbc-tx.xml增加包扫描和tx:annotation-driven