一:隔离级别
项目中用到的数据库是mysql,默认的隔离级别是REPEATABLE_READ
重复读,pgsql与oracle默认隔离级别READ_COMMITTED
下面是spring的五种隔离级别,默认是和使用数据库的类型相同。
DEFAULT(-1),
READ_UNCOMMITTED(1),
READ_COMMITTED(2),
REPEATABLE_READ(4),
SERIALIZABLE(8);
public class A{
@Transactional(isolation = Isolation.SERIALIZABLE)
public void methodA() {
userMapper.insert();
}
public void methodB() {
userMapper.insert()
}
当执行方法methodA的时候,methodB的接口去select是可以查到数据的,但是对应user表中的add/update/delete是会在等待的,无法执行。这个就是串行执行的隔离级别。
public class A{
@Transactional(isolation = Isolation.SERIALIZABLE)
public void methodA() {
userMapper.insert()
methodB();
}
public void methodB() {
userMapper.insert()
}
在同一个类中是可以执行完成的
public class A{
@Transactional(isolation = Isolation.SERIALIZABLE)
public void methodA() {
userMapper.insert()
methodB();
}
}
public class B{
public void methodB() {
userMapper.insert()
}
@Transactional
public void methodC() {
userMapper.insert()
}
}
这里类A中methodA调用类B方法methodB/methodC都是可以执行完成的;
public class A{
@Transactional(isolation = Isolation.SERIALIZABLE)
public void methodA() {
userMapper.insert()
methodB();
}
}
public class B{
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
userMapper.insert()
}
}
这里类A中methodA调用类B方法methodB方法就会发生死锁了,因为Propagation.REQUIRES_NEW这个传播级别是自己
被REQUIRES_NEW标记的方法会新建事务,如果当前存在事务,把当前事务挂起,等待新开事务完成后,被挂起的事务再恢复执行。
这里是methodA调用methodB,当执行到methodB时候,methodA事物挂起,等待methodB执行完成后,methodA被挂起的事物在恢复执行。
但是这里由于methodA的隔离级别是Isolation.SERIALIZABLE
串行执行,导致死锁。
public class A{
public void methodA() {
userMapper.insert()
methodB();
}
}
public class B{
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
userMapper.insert()
}
}
这里methodA()方法无事物,methodB()方法@Transactional(propagation = Propagation.REQUIRES_NEW)这个传播特性是新的事物,这里methodA()无事物执行,methodB()有事物,可以回滚。