关于事务的一些理解
事务就是逻辑上的一组操作,要么都执行,要么都不执行
拜个大神
Spring的共同创始人Juergen Hoeller,Spring事务的源码几乎都是他写的,膜拜大神。
事务的ACID
- 原子性:事务是最小的执行单位,不可分割;一个事务中的所有操作,要么全部完成,要么全部不完成;发生错误就回滚
- 一致性:事务执行前后,数据保持一致
- 隔离性:并发访问数据库时,一个用户的事务不被其他干扰;有四个级别,包括未提交读、提交读、可重复读、串行化
- 持久性:事务被提交后,对数据库中数据的改变是永久的,即使系统炸了也不会丢失
Spring事务管理
- PlatformTransactionManager: 事务管理器
- TransactionDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)
- TransactionStatus: 事务运行状态
PlatformTransactionManager可以看作事务上层的管理者,TransactionDefinition和TransactionStatus可以看作事务描述。
PlatformTransactionManager可以根据TransactionDefinition的定义如隔离级别、传播行为等进行事务管理,TransactionStatus则用来获取相应状态如是否新事务、是否回滚等。
PlatformTransactionManager:事务管理接口
PlatformTransactionManager接口定义了三个方法:
package org.springframework.transaction;
import org.springframework.lang.Nullable;
public interface PlatformTransactionManager {
//获得事务
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
//提交事务
void commit(TransactionStatus var1) throws TransactionException;
//回滚事务
void rollback(TransactionStatus var1) throws TransactionException;
}
TransactionDefinition:事务属性(定义)
事务管理器PlatformTransactionManager里获取事务时所用的方法getTransaction,其中参数就是TransactionDefinition,定义了一些基本的事务属性,可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。
事务属性包含了 5 个方面:
- 隔离级别
- 传播行为
- 回滚规则
- 是否只读
- 事务超时
接口中定义了 5 个方法和一些属性
package org.springframework.transaction;
import org.springframework.lang.Nullable;
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
// 返回事务的传播行为,默认值为 REQUIRED。
int getPropagationBehavior();
//返回事务的隔离级别,默认值是 DEFAULT
int getIsolationLevel();
// 返回事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
int getTimeout();
// 返回是否为只读事务,默认值为 false
boolean isReadOnly();
@Nullable
String getName();
}
一般开发都是@Transactional开启
事务传播行为
传播行为是为了解决事务方法间相互调用的问题。
例如,A事务方法调用B事务方法,此时B是继续在A中运行,还是自己另外开启一个新事务运行,由B的事务传播行为决定。
事务传播行为有 7 种:
- PROPAGATION_REQUIRED
如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。
@Transactional默认的传播行为
有两点注意:
- 外部方法没有开始事务时,PROPAGATION_REQUIRED的内部方法回新开启自己的事务,且互不干扰,相互独立
- 外部方法有开启事务,且被PROPAGATION_REQUIRED,那么所有被PROPAGATION_REQUIRED修饰的方法,不管内外,都属于同一个事务,有一个方法回滚,整个事务回滚
举个例子,b 回滚,a 也回滚,a b 属于同一事务
@Service
Class A {
@Autowired
B b;
@Transactional(propagation = Propagation.REQUIRED)
public void aMethod {
//do something
b.bMethod();
}
}
@Service
Class B {
@Transactional(propagation = Propagation.REQUIRED)
public void bMethod {
//do something
}
}
PROPAGATION_SUPPORTS
如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。
PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
- PROPAGATION_REQUIRES_NEW
重新创建一个新的事务,如果当前存在事务,暂停当前的事务。
即不管外部有没有开启事务,PROPAGATION_REQUIRES_NEW都会新开一个事务,且相互独立,互不干扰。
举个例子,a 回滚,b 不会跟着回滚,因为是两个事务
@Service
Class A {
@Autowired
B b;
@Transactional(propagation = Propagation.REQUIRED)
public void aMethod {
//do something
b.bMethod();
}
}
@Service
Class B {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void bMethod {
//do something
}
}
- PROPAGATION_NOT_SUPPORTED
以非事务的方式运行,如果当前存在事务,暂停当前的事务。
- PROPAGATION_NEVER
以非事务的方式运行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED
当前存在事务,就在嵌套事务内执行,即在外部方法开启事务的情况下,在内部开启一个新的事务,作为嵌套事务存在
若没有事务,则单独开启一个事务,和 Propagation.REQUIRED 效果一样。
b 回滚,a 也回滚
@Service
Class A {
@Autowired
B b;
@Transactional(propagation = Propagation.REQUIRED)
public void aMethod {
//do something
b.bMethod();
}
}
@Service
Class B {
@Transactional(propagation = Propagation.NESTED)
public void bMethod {
//do something
}
}
事务隔离级别
隔离级别有 4 种:
- Read Uncommitted(读取未提交):最低级别,可能导致脏读、幻读或不可重复读
- Read Committed(读取已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但不可重复读,幻读可能发生
- Repeatable Read(可重读):对同一字段的多次读取结果都是一致的,除非被本身修改,可以阻止脏读、不可重复读,但幻读可能发生
- Serializable(可串行化):最高级别,不会产生事务干扰,但影响性能
脏读:一个事务中访问到了另外一个事务未提交的数据
幻读:前后多次读取,数据总量不一致,如一个事务读了几行数据,另一个并发事务插入新数据,之后第一个事再次务查询发现多了原本不存在的数据
不可重复读:前后多次读取,数据内容不一致
事务回滚规则
定义哪些异常会导致事务回滚而哪些不会,默认运行时异常(RuntimeException 的子类)回滚,error也回滚。
@Transactional注解原理
基于AOP实现,AOP基于动态代理实现,对象实现接口,默认用JDK动态代理,没有接口使用CGLIB。
自己实现的Spring框架下CGLIB中关于@Transactional的实现
/**
* 获取事务状态对象
* @param object
* @param method
* @return
*/
private TransactionStatus geTransactionStatus(Object object,Method method){
TransactionStatus status = new TransactionStatus();
//不开启事务
status.isNeed = false;
if (transactionManager != null && (object.getClass().isAnnotationPresent(Transactional.class) || method.isAnnotationPresent(Transactional.class))){
status.isNeed = true;
//类有事务注解
if ((object.getClass().isAnnotationPresent(Transactional.class))){
//获取事务注解
Transactional transactional = object.getClass().getAnnotation(Transactional.class);
//事务隔离级别
status.isolationLevel = transactional.Isolation();
//事务传播级别
status.propagationLevel = transactional.Propagation();
//回滚异常类型
status.rollbackFor = transactional.rollbackFor();
}
//方法有事务注解
if(method.isAnnotationPresent(Transactional.class)){
Transactional transactional = method.getAnnotation(Transactional.class);
status.isolationLevel = transactional.Isolation();
status.propagationLevel = transactional.Propagation();
status.rollbackFor = transactional.rollbackFor();
}
}
return status;
}
TransactionStatus:事务状态
用来记录事务的状态,获取相应信息
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事务
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}