一、Spring中事务的隔离级别
Spring 提供了 5 种不同的事务隔离级别,每种级别都代表了一种不同的隔离程度:
1.Isolation.DEFAULT:默认级别,使用数据库默认的隔离级别。不同的数据库默认隔离级别可能不同。
2.Isolation.READ_UNCOMMITTED:最低的隔离级别,事务可以读取未提交的数据,也就是脏读(Dirty Read)。
3.Isolation.READ_COMMITTED:事务只能读取已经提交的数据,可以避免脏读,但是可能会出现不可重复读(Non-repeatable Read)。
4.**Isolation.REPEATABLE_READ:**事务可以多次读取同一数据,保证了数据一致性,但是可能会出现幻读(Phantom Read)。
5.**Isolation.SERIALIZABLE:**最高的隔离级别,事务串行执行,避免了脏读、不可重复读和幻读,但是性能较差。
不可重复度:针对的是数据的修改,前后两次读到的数据不一样。
幻读:针对数据的添加和删除,前后读到的数据数量的不同。
二、七种传播级别
事务的传播级别(Propagation Level)是指在多个事务方法相互调用时,事务如何传播的规则。Spring 提供了 7 种不同的传播级别,每种级别都代表了一种不同的事务传播行为:
1、Propagation.REQUIRED:默认值。如果当前存在事务,则加入该事务;如果不存在事务,则创建一个新的事务。
2、Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果不存在事务,则不会创建一个新的事务。
3、Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果不存在事务,则抛出一个异常。
4、Propagation.REQUIRES_NEW:无论当前是否存在事务,都会创建一个新的事务。如果当前存在事务,则挂起当前事务,执行新的事务,新的事务执行完毕后再恢复当前事务。
5、Propagation.NOT_SUPPORTED:如果当前存在事务,则挂起当前事务,以非事务状态执行该方法;执行完毕后再恢复当前事务。
6、Propagation.NEVER:如果当前存在事务,则抛出一个异常;如果不存在事务,则以非事务状态执行该方法。
7、Propagation.NESTED:如果当前存在事务,则在当前事务中嵌套一个新的事务;如果不存在事务,则创建一个新的事务。嵌套的事务可以独立提交或回滚,但是如果外层事务回滚,则内层事务也会回滚。
三、七种传播级别的举例
1、Propagation.REQUIRED:
@Transactional
public void methodA(){
// do something
methodB();
// do something
}
@Transactional
public void methodB(){
// do something
}
在这个例子中,方法 A 和方法 B 都使用了默认的传播级别 Propagation.REQUIRED,即如果当前存在事务,则加入该事务;如果不存在事务,则创建一个新的事务。当调用 methodB() 时,methodB() 将会加入 methodA() 的事务中,因为 methodA() 已经开启了一个事务。当 methodB() 结束时,methodA() 的事务也将结束。如果 methodB() 抛出了异常,则 methodA() 也将回滚。
2、Propagation.SUPPORTS:
@Transactional
public void methodA(){
// do something
methodB();
// do something
}
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB(){
// do something
}
在这个例子中,方法 A 使用了默认的传播级别 Propagation.REQUIRED,而方法 B 使用了传播级别 Propagation.SUPPORTS,即如果当前存在事务,则加入该事务;如果不存在事务,则不会创建一个新的事务。当调用 methodB() 时,它将加入 methodA() 的事务中,因为 methodA() 已经开启了一个事务。如果 methodB() 抛出了异常,则 methodA() 也将回滚。
3、Propagation.MANDATORY:
@Transactional
public void methodA(){
// do something
methodB();
// do something
}
@Transactional(propagation = Propagation.MANDATORY)
public void methodB(){
// do something
}
在这个例子中,方法 A 使用了默认的传播级别 Propagation.REQUIRED,而方法 B 使用了传播级别 Propagation.MANDATORY,即如果当前存在事务,则加入该事务;如果不存在事务,则抛出一个异常。当调用 methodB() 时,它将加入 methodA() 的事务中,因为 methodA() 已经开启了一个事务。如果 methodA() 没有事务,则 methodB() 将抛出一个异常。
4、Propagation.REQUIRES_NEW:
@Transactional
public void methodA(){
// do something
methodB();
// do something
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB(){
// do something
}
在这个例子中,方法 A 使用了默认的传播级别 Propagation.REQUIRED,而方法 B 使用了传播级别 Propagation.REQUIRES_NEW,即无论当前是否存在事务,都会创建一个新的事务。当调用 methodB() 时,它将在一个新的事务中执行,与 methodA() 的事务无关。当 methodB() 结束时,仅仅会提交 methodB() 的事务,而不会影响 methodA() 的事务。
5、Propagation.NOT_SUPPORTED:
@Transactional
public void methodA(){
// do something
methodB();
// do something
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodB(){
// do something
}
在这个例子中,方法 A 使用了默认的传播级别 Propagation.REQUIRED,而方法 B 使用了传播级别 Propagation.NOT_SUPPORTED,即如果当前存在事务,则挂起当前事务,以非事务状态执行该方法;执行完毕后再恢复当前事务。当调用 methodB() 时,它将挂起 methodA() 的事务,以非事务状态执行 methodB(),当 methodB() 结束时,恢复 methodA() 的事务。
6、Propagation.NEVER:
@Transactional
public void methodA(){
// do something
methodB();
// do something
}
@Transactional(propagation = Propagation.NEVER)
public void methodB(){
// do something
}
在这个例子中,方法 A 使用了默认的传播级别 Propagation.REQUIRED,而方法 B 使用了传播级别 Propagation.NEVER,即如果当前存在事务,则抛出一个异常;如果不存在事务,则以非事务状态执行该方法。当调用 methodB() 时,如果 methodA() 已经开启了一个事务,则 methodB() 将抛出一个异常;如果 methodA() 没有事务,则 methodB() 将在非事务状态下执行。
7、Propagation.NESTED:
@Transactional
public void methodA(){
// do something
methodB();
// do something
}
@Transactional(propagation = Propagation.NESTED)
public void methodB(){
// do something
}
在这个例子中,方法 A 使用了默认的传播级别 Propagation.REQUIRED,而方法 B 使用了传播级别 Propagation.NESTED,即如果当前存在事务,则在当前事务中嵌套一个新的事务;如果不存在事务,则创建一个新的事务。当调用 methodB() 时,它将在 methodA() 的事务中嵌套一个新的事务,这个新的事务可以独立提交或回滚,但是如果 methodA() 的事务回滚,则 methodB() 的事务也会回滚。