事务的四个隔离级别:
首先要说下三个概念:脏读、不可重复读、幻读
- 脏读(Dirty Read)。脏读是指一个事务读取了另一个事务未提交的数据,这种数据有可能在将来被回滚,导致读取的数据是无效的。
- 不可重复读(Unrepeatable Read)。不可重复读是指在一个事务内,两次读取同一数据集合时,由于另一个事务的修改并提交了数据,导致第一次和第二次读取到的数据不一致。
- 幻读(Phantom Read)。幻读是指在一个事务内,多次执行同一查询时,由于另一个事务插入了新的数据行或删除了符合查询条件的行,导致查询结果集的数量或内容发生变化,就像发生了幻觉一样。
隔离级别 | 异常情况 | 异常情况 | |
---|---|---|---|
读未提交 | 脏读 | 不可重复读 | 幻读 |
读已提交 | 不可重复读 | 幻读 | |
可重复读 | 幻读 | ||
序列化 |
一、Read Uncommitted -- 读取未提交内容
-
一个事务可以查看到未提交的内容
-
常产生脏读问题(脏读:读取到其他事务未提交(执行)的内容)
对同一数据表开启A、B两个事务(A、B事务交叉) start transaction
A事务只查询数据表中内容,B事务做增删改操作但不commit(提交)
A事务依旧可以查询到表中的数据改变(查询到未提交的内容--脏读)
二、Read Committed -- 读取提交内容
-
一个事务只能查看已提交的内容
-
常产生不可重复读的问题(不可重复读:同一事务中执行相同的select语句得到(修改)不同的结果)
对同一数据表开启A、B两个事务(A、B事务交叉) start transaction
A事务只查询数据表中内容,B事务做增删改操作但不commit(提交)
A事务查询不到表中的数据改变的内容
B事务提交
A查到的数据改变(A两次查询,产生不同的结果--不可重复读)
三、Repeatable Read -- 可重读
-
同一事务的多个实例并发读取数据时得到同一结果
-
MySQL的默认事务隔离级别
-
常产生幻读问题(幻读:多次读取时产生不同结果(插入或删除))
对同一数据表开启A、B两个事务(A、B事务交叉) start transaction
A事务只查询数据表中内容,B事务做增删改操作但不commit(提交)
A事务查询不到表中的数据改变的内容
B事务提交
A事务查询不到表中的数据改变的内容
A提交
A可查询到表中数据的改变
四、Serializable -- 可串行化
-
最高隔离级别
-
给事务加上共享锁,同时只能有一个事务操作,解决幻读问题
-
会导致大量超时和锁竞争问题
开启A事务
开启B事务时无法增删该操作
Spring的的七种事务传播机制:
一、 REQUIRED
REQUIRED是默认的事务传播行为。如果当前存在事务,那么该方法将会在该事务中运行;如果当前没有事务,那么它会启动一个新的事务。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
// 使用REQUIRED传播机制
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 方法A的业务代码...
// 调用方法B
serviceB.methodB();
// 如果methodB出现错误,那么methodA和methodB的操作都会回滚。
}
}
@Service
public class ServiceB {
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
// 方法B的业务代码...
}
}
二、 SUPPORTS
如果当前存在事务,那么该方法将会在该事务中运行;如果当前没有事务,那么它可以以非事务方式执行。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(propagation = Propagation.SUPPORTS)
public void methodA() {
// 方法A的业务代码...
serviceB.methodB();
// 无论methodB是否出现错误,methodA的操作都不会回滚。
}
}
@Service
public class ServiceB {
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {
// 方法B的业务代码...
}
}
三、 MANDATORY
MANDATORY传播行为要求方法必须在一个现有的事务中执行,如果没有事务就抛出异常。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(propagation = Propagation.MANDATORY)
public void methodA() {
// 方法A的业务代码...
serviceB.methodB();
// 如果没有现有事务,会抛出异常。
}
}
@Service
public class ServiceB {
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() {
// 方法B的业务代码...
}
}
四、 REQUIRES_NEW
REQUIRES_NEW传播行为总是会启动一个新的事务。如果有一个事务正在运行,那么这个事务将会被挂起。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodA() {
// 方法A的业务代码...
serviceB.methodB();
// methodB在新的事务中运行,无论是否出错,都不会影响methodA的事务。
}
}
@Service
public class ServiceB {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 方法B的业务代码...
}
}
五、 NOT_SUPPORTED
NOT_SUPPORTED传播行为总是以非事务方式执行,如果有一个事务正在运行,那么这个事务将会被挂起。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodA() {
// 方法A的业务代码...
serviceB.methodB();
// 无论methodB是否出错,methodA的操作都不会回滚,因为它们不在同一个事务中。
}
}
@Service
public class ServiceB {
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodB() {
// 方法B的业务代码...
}
}
六、 NEVER
NEVER传播行为要求方法以非事务方式执行,如果有一个事务正在运行,将会抛出异常。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(propagation = Propagation.NEVER)
public void methodA() {
// 方法A的业务代码...
serviceB.methodB();
// 如果有事务正在运行,会抛出异常。
}
}
@Service
public class ServiceB {
@Transactional(propagation = Propagation.NEVER)
public void methodB() {
// 方法B的业务代码...
}
}
七、 NESTED
NESTED传播行为在一个嵌套事务中执行,如果一个事务正在运行,那么它将在一个嵌套事务中执行。这个嵌套事务是可以独立提交或回滚的。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional(propagation = Propagation.NESTED)
public void methodA() {
// 方法A的业务代码...
serviceB.methodB();
// methodB在嵌套事务中运行,如果出错,只有嵌套事务会回滚,不会影响methodA的事务。
}
}
@Service
public class ServiceB {
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
// 方法B的业务代码...
}
}