什么是隔离级别

在多事务的并发场景下,多个事务可能会对同一数据进行读写,从而破坏了事务的隔离性,导致数据出现各种问题。例如:
类型1:
在这里插入图片描述
T5时刻事务1回滚了事务,所以事务2的丢失就更新了。
现在已经优化了回滚机制,多以回滚所带来的更新丢失已经克服了,所以这里不再讨论。

类型2:

在这里插入图片描述
T5时刻事务提交,将库存修改为99,这样事务2对数据的修改就丢失了。

所谓隔离级别就是对事的务执行从数据库层面添加限制条件,共有四个隔离级别,越往后对数据库的限制越大,隔离性越好,数据越安全,但是会使得数据库的性能降低。

级别一:未提交读

未提交读,就是说不用等到某个事务执行完毕,其他事务就可以读取到改事务更改后的数据。这样,在上图的T3时刻,事务2扣减库存时就不会从100减,因为早在T2时刻,事务1已经对库存进行了扣减。

未提交读是最低的一个隔离级别,所以仍有些问题不可避免,如下图执行所带来的脏读问题

在这里插入图片描述
由于采用未提交读的隔离级别,所以事务2读取到的并不是事务1执行完成后的结果数据。因为事务2执行扣减库存操作时,事务1正在执行还未提交,所以事务1可能还会对数据进行修改,或者回滚数据(如上图T5时刻事务1回滚了数据),这样事务2实际上读取的是错误的数据,这就称之为脏读,这样的数据称之为脏数据
脏读是个很严重的问题,并且在未提交读这种隔离级别下很容易出现,所以我们一般不会采用这个隔开级别,像Oracle数据库直接没有提交这种隔离级别的保护。

级别二:读写提交

写提交是值,只有当数据修改(写)的事务提交/回滚以后,其他事务才能读取到修改后的数据,否则读取的都是原来的数据。如下图执行便克服了脏读的问题:
在这里插入图片描述

同样作为第二个级别仍有些问题不可避免,如下图执行所带来的不可重读丢问题,如下图执行所示
在这里插入图片描述
因为采取了读写提交的隔离级别,所以事务2不知道事务1对数据做了什么操作。这样在T3时刻和T5时刻,事务2所能读取的数据是不一样的,这就是不可重读读。
如上图,当数据为0,两个事务又都要减时,就会出错了。但是如果库存为2,那么这个问题就不会出现,所以读写提交已经在很大程度上保证了并发事务执行的数据一致性。

级别三:可重复读

比起读写提交,可重复读对事务执行的限制更进一步,当事务对某个数据进行写操作时就对该数据加锁,其他事务将无法读写该数据。只有当写数据的事务提交/回滚后其他事务才能才做该数据,如下图执行,如此就客服了不可重复读的问题
在这里插入图片描述
还是一样,作为第二个级别仍有些问题不可避免,如下图执行所带来的幻读问题,如下图执行所示
在这里插入图片描述
幻读不可重复读有一定的相似之处,都是同一事务前后两次读取的结果不一致。但是幻读的问题不是针对单一数据的读取,而是对数据的聚合操作。在可重复读的隔离级别中,当存在某一事务修改数据时,该数据会被加锁,以保证其他事务无法读取,但是如果是一个聚合操作呢?比如上图所示的求和查询。锁并没有加载整个数据表上,而是在被修改某些条记录上。

由此我们可以知道,幻读不可重复读相似,区别就是事务操作的对象不同。

级别四:串行化

终极限制条件,禁止事务的并发执行,只允许事务串行执行,一切问题全部消失!
但是!!数据库的性能将会被限制到一个极低的水平,所以基本不会用。

总结

生产中要根据业务的情形来使用隔离级别,随着隔离级别增高,数据库的性能会直线下降,所以运用需要权衡。
比如,在Spring中,默认的隔离级别是读写提交

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐