事务隔离级别
针对隔离性的强度
,共有以下四种级别
- 串行化(Serializable):指
对同一行记录,读写操作都会加锁
。当出现读写锁冲突的时候,后访问的事务必须等待前一个事务执行完成,才能继续执行 - 可重复度读(Repeatable read)(MySQL默认模式):
一个事务执行过程中看到的数据,总是与这个事务在启动的时候看到的数据是一致的
,在可重复读的隔离级别下,未提交变更对其它事务是不可见的。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读 - 读已提交(Read committed)(Oracle、SQL Server默认模式):一个
事务提交之后
,它做的变更才会被其他事务看到
,可防止脏读 - 读未提交(Read uncommitted):一个
事务还没有提交
,它做的变更就能被其他的事务看到
因此,有下述三个事务的隔离级别
脏读
:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据- 出现:在写入数据后,但是没有提交,在这个时候读取数据,但是过后又把这条数据给删除了,再进行提交,那么之前读取的数据是第一次执行写操作后的所有数据
- 原因: Read uncommitted(允许读未提交的数据)
- 解决方案: Read committed (表级读锁)
不可重复读
:读取过程中单个数据发生了变化,事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致- 出现:同一个数据两次读取的内容不一样
- 解决方案: Repeatable read (行级写锁)
幻读
:读取过程中数据条目发生了变化,系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读- 出现:先进行读数据,但是同时另一方进行写数据(删除,修改,插入等),再次一读,发现多数据或者是少数据了,总之就是出现了一闪而过的数据,比如之前读取的数据刷新过后,有一些数据没有了或者出现了新的。
- 解决方案: Serializable (表级写锁)
不可重复读的和幻读很容易混淆,不可重复读侧重于修改
,幻读侧重于新增或删除
。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
Read uncommitted | 可能出现 | 可能出现 | 可能出现 |
Read committed | 不会出现 | 可能出现 | 可能出现 |
Repeatable read | 不会出现 | 不会出现 | 可能出现 |
Serializable | 不会出现 | 不会出现 | 不会出现 |
声明式事务
@Transactional 属于声明式事务
声明式事务概念:基于AOP面向切面的
,它将具体业务与事务处理部分解耦,代码侵入性很低
编程式事务
@Service
public class TransactionDemo {
@Autowired
private TransactionTemplate transactionTemplate;
public void programmaticUpdate() {
// 这里也可以使用Lambda表达式
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
}
}
如果你的程序中需要针对某种特定异常有特殊操作,那么可以使用try…catch,切记此时需要调用TransactionStatus的setRollbackOnly方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
@Service
@Slf4j
public class TransactionDemo {
@Autowired
private TransactionTemplate transactionTemplate;
public void programmaticUpdate() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {<