事务隔离级别
![](https://img2023.cnblogs.com/blog/3120037/202303/3120037-20230309181045426-2060599959.png)
读未提交、读已提交、可重复读、序列化
1). 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
2). 设置事务隔离级别
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
注意:事务隔离级别越高,数据越安全,但是性能越低。
串行化是指:我在执行并发事务操作的时候,我只允许一次一个事物来操作,a事务操作b事务时,只有当a事务操作完成提交之后,b事务才能够操作。这种隔离级别可以规避任何并发问题,但是性能最低。
一般采用数据库的默认级别。
举例:假如有两个事物,a事务和b事务,都对某张表账户表ac表主键为id进行操作。
设置隔离级别 read uncommited 这种隔离级别为读未提交,会出现“脏读”的情况。开启a事务,然后开启b事务,
a事务里面查询账户表id为1的money值,发现为2000,b事务对这个id的money进行加1000,此时,a,b事务都未提交,在a事务里再次查询账户表id为1的money值,发现变为3000,出现“脏堵”,也就是读了b事务未提交的数据,提交ab事务。
所以设置隔离级别为read uncommited会出现“脏读”。
为了解决这个问题,可以将隔离级别设置为read commited,但这种隔离级别会出现“不可重复读”。恢复账户表,同样开启a事务,然后再开启b事务。
a事务里面查询账户表表id为1的money值,发现为2000,b事务对这个id的money进行修改为3000,此时,a,b事务都未提交,在a事务里面继续查询账户表id为1的money值,发现即使b事务未提交,a事务查到的还是2000,避免了“脏堵”。但是提交b事务后,
在a事务里面查询账户表id为1的money值发现变为了3000,刚开始查是2000,而现在查又是3000,一个事物里面读到了两个不同的值,也就是出现了“不可重复读”,记得提交a事务。
为了解决这个问题,可以将隔离级别设置为repeatable read,但这种隔离级别会出现“幻读”。恢复账户表,同样开启a事务,然后再开启b事务。
a事务里面查询账户表id为2的记录,发现返回记录为空,接着b事务增加一条id为2,money为3000的账户信息并提交,此时a事务以为没有2这条记录执行插入操作,发现报错:主键冲突,又查一下账户表id为2的记录,发现还是为空,虽然两次查询都是空,也就是说避免了“不可重复读”,但是。插入这条不存在的数据时又提示存在,也就是出现了“幻读”。记得提交a事务。
为了解决这个问题,可以将隔离级别设置为serializable,这种隔离级别是最安全的,但是性能最低。恢复账户表,同样开启a事务,然后再开启b事务。
a事务里面查询账户表id为2的记录,发现返回记录为空,接着b事务增加一条id为2,money为3000的账户信息,发现b事务一直无响应,接着在a事务里面执行b事务执行的增加记录,执行成功,并提交,同时发现b事务立即响应并返回主键冲突的错误,这就相当于解决了“幻读”的问题,但是,b事务执行操作时需要等到a事务执行完才能响应并执行下面的操作。所以这样在高并发的情况下,性能是极低的。
因此虽然设置高的隔离级别可以解决数据的安全性问题,但是数据库的访问性能又降低了。为了平衡数据的安全性和数据库的性能开销,我们按照数据库的默认隔离级别REPEATABLE READ即“可重复读”来操作事务即可。