事务的隔离级别
名词的含义
名词 | 含义 | 原因 |
---|---|---|
脏读 | 一个事务读取了另一个事务还没有提交的数据 | 一个事务对某数据进行更新,但并未提交,另一事务读取到了该数据,但是前一个事务如果回滚,那么后一个事务就读取到了错误数据 |
不可重复读 | 一个事务多次读取同一个数据,结果不同 | 一个事务在2次读取某数据之间时,另一个事务对数据进行了更新,导致前一个事务前后读取数据不一致 |
幻读 | 一个事务多次查询符合某一条件的数据,结果不同 | 一个事务在2次查询某一条件的数据之间时,另一个事务插入了一条符合该条件的数据,导致前一个事务前后查询数据不一致 |
隔离级别
隔离级别 | 含义 | 描述 |
---|---|---|
SERIALIZABLE | 串行化 | 事务串行执行,消耗最大 |
REPEATABLE READ | 可重复读 | 避免不可重复读,但是会出现幻读 |
READ_COMMITTED | 读已提交 | 避免脏读,但是会出现不可重复读和幻读 |
READ_UNCOMMITTED | 读未提交 | 会出现脏读,不可重复读和幻读 |
DEFAULT | 默认 | 使用数据库默认的事务隔离级别 |
事务的传播行为
传播行为 | 描述 |
---|---|
PROPAGATION_REQUIRED | 如果上下文已存在事务, 就加入该事务; 否则新建事务 |
PROPAGATION_SUPPORTS | 如果上下文已存在事务, 就加入该事务; 否则以非事务方式执行 |
PROPAGATION_NOT_SUPPORTED | 如果上下文已存在事务, 就挂起该事务, 以非事务方式执行完, 再恢复上下文事务; 否则直接以非事务方式执行 |
PROPAGATION_MANDATORY | 如果上下文已存在事务, 就加入该事务; 否则抛异常 |
PROPAGATION_NEVER | 如果上下文已存在事务; 就抛异常; 否则以非事务方式执行 |
PROPAGATION_REQUIRES_NEW | 如果上下文已存在事务, 就将上下文事务挂起,然后新建事务,直到新事务执行完,再恢复上下文事务; 否则新建事务 |
PROPAGATION_NESTED | 如果上下文已存在事务,就嵌套事务; 否则新建事务 |
嵌套事务
嵌套事务是子事务套在父事务中执行, 子事务是父事务的一部分. 在进入子事务之前, 父事务会建立一个回滚点.
如果子事务回滚, 父事务会回滚到进入子事务之前建立的回滚点
如果父事务回滚, 子事务也会跟着回滚. 因为父事务结束之前, 子事务不会提交.
提交事务时, 子事务先提交,然后父事务在提交
事务的使用
- Spring 注入
PlatformTransactionManager
的某一个具体实现类JtaTransactionManager
或DataSourceTransactionManager
等 - 使用
@Transactional
标注在某一方法上 - 或者使用
TransactionTemplate
来进行细粒度化的操作 - Spring 中事务默认回滚
RuntimeException
和Error
的异常
TransactionAspectSupport#invokeWithinTransaction()
->
TransactionAspectSupport#completeTransactionAfterThrowing()
->
DefaultTransactionAttribute#rollbackOn()
注意
在 Spring 中, 同一个类中的方法, 一个方法直接调用另一个方法, 第二个方法上的@Transactional是无效的
例如 :
@Service
public class MyServiceImpl implements MyService {
public void test1() {
test2();
}
@Transactional
public void test2() {
}
}
@RestController
public class MyController {
@Autowired
MyService myService;
@GetMapping("/test1")
public Object test1(){
myService.test1();
return "ok";
}
@GetMapping("/test2")
public Object test2(){
myService.test2();
return "ok";
}
}
在MyController#test1()
中, 通过myService.test1()
间接调用myService#test2()
, @Transactional
是不生效的
在MyController#test2()
中, 直接调用myService#test2()
,@Transactional
生效
另外传播行为和隔离级别也是一样, 因为它们的前提是@Transactional
生效