博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据库之事务之间的隔离
阅读量:6417 次
发布时间:2019-06-23

本文共 4408 字,大约阅读时间需要 14 分钟。


layout: post title: "数据库之事务之间的隔离" subtitle: " "隔离级别"" date: 2018-10-21 07:00:00 author: "青乡" header-img: "img/post-bg-2015.jpg" catalog: true tags: - database - transaction - transaction isolation - spring

数据库的并发和事务

Two-phase locking is the most common transaction concurrency control method in DBMSs, used to provide both serializability and recoverability for correctness. In order to access a database object a transaction first needs to acquire a lock for this object. Depending on the access operation type (e.g., reading or writing an object) and on the lock type, acquiring the lock may be blocked and postponed, if another transaction is holding a lock for that object.

什么是事务

一个用户,一次请求,一个连接,一个线程,一个事务。


事务的4个特性,即ACID:

1.atomic //操作原子
要么全部执行,要么全部不执行。

2.consistent //数据一致性

一致性指的是准确性。

以下情况,可以解释数据一致性: 1)原子性不能保证数据一致性 事务1和事务2各自给账户A加/转账100,账户A本来应该收200。但是由于不同的事务隔离级别的原因,可能导致事务2读的数据是旧的数据,从而把事务1的写给覆盖掉了,最终账户A收100。

2个事务都是原子,但是不能保证数据是正确性/一致性。

2)数据不能违反数据库的各种约束,否则数据不正确,数据也插不进去 什么约束呢?比如,字段类型是整数,你插个字符串,就报错了。比如,主键非空,你插入数据的时候主键没有值,就报错了。

3.isolation //事务之间的隔离和隔离级别

4.duration //数据持久化到数据库/磁盘

什么是事务之间的隔离

不同事务的数据,数据的隔离性。

1.多个事务

2.操作的同一个数据
3.会出现什么后果?
这个后果的不同,就是隔离级别的不同。

会出现哪几种后果?

脏读

dirty read,其实就是读到了另外一个事务的未提交的数据。即错误的数据,不存在的数据——因为事务2的更新sql回滚了。

具体来说,就是事务1有2个同样的查询sql,事务2有1个更新sql。事务2的更新sql发生在事务1的2个同样查询的sql的中间,导致事务1-后面查询读到了事务2的未提交的数据。

总结,同一个事务的2个同样的查询sql,查到的数据不一样,这是其一;其二,更重要的一点是,第二次读的数据是数据库中不存在的数据。第二点更为重要,因为脏读的意思就是读到了不存在的数据,而第一点查到的数据不一样这种情况,在非重复读这种后果里也是这样。

最佳实践,实际情况下,也就是真正应用的时候是,这种情况比较少应用到,因为一般情况下,我们肯定是要看到提交之后的数据,没提交就不需要看到嘛。实际上,数据库厂商,mysql oracle默认隔离级别都不是这种情况,而是读已经提交的数据。


隔离级别

脏读对应的隔离级别就是读了未提交的数据,即read uncommit。


怎么解决读未提交的问题?

事务2-更新数据的时候,上锁,并且直到提交之后,才释放锁——目的就是为了确保更新数据的时候,不让其他事务读数据。

能解决这个问题,就避免了也不会出现读未提交的情况。

非重复读

Non-repeatable read,就是2次读的数据不一样。非重复读,就是2次读的数据不一样。

例子还是前面的例子。只是事务2的更新sql提交了。

现在事务1的2次查询数据不一样,因为事务2的更新sql已经提交了,事务1-后面查询就可以看到新的数据了。

At the SERIALIZABLE and REPEATABLE READ isolation levels, the DBMS must return the old value for the second SELECT.

At READ COMMITTED and READ UNCOMMITTED, the DBMS may return the updated value;

this is a non-repeatable read.


隔离级别

非重复读对应的隔离级别是读了已经提交的数据,即read commit。


怎么解决2次读的数据不一样的问题?

如果解决了非重复读的问题,即事务1的2次读的数据都是旧的数据,那么这个时候就叫重复读,对应的隔离级别是repeat read。重复读的意思,就是确保2次读的数据一样。

怎么确保呢,就是事务1操作期间,上锁,直到事务1提交——目的就是为了,不允许其他事务更新数据。

注意,这里的上锁,上的是行锁,就是说针对这一行的数据,其他事务不允许更新它——除非事务1已结提交。

幻读

Phantom reads,幻读。

sql代码的例子,稍微有点改变,就是现在的select是查一个范围的数据,where 条件是一个范围。事务2更新了这个范围的数据,并且已经提交了。导致事务1的2次读的数据不一样,这个就叫做幻读。

前面的不重复读/重复读,针对的数据是同一个记录的数据。这个时候的锁,是行锁row lock。

幻读,针对的数据是同一个范围的数据(例如,同一个表的数据)。这个时候的锁,是范围锁range lock。

所以行锁,其他事务还可以插入新的记录。而范围锁/表锁,在指定范围内不允许插入新的记录。

Note that Transaction 1 executed the same query twice. If the highest level of isolation were maintained, the same set of rows should be returned both times, and indeed that is what is mandated to occur in a database operating at the SQL SERIALIZABLE isolation level. However, at the lesser isolation levels, a different set of rows may be returned the second time.

In the SERIALIZABLE isolation mode, Query 1 would result in all records with age in the range 10 to 30 being locked, thus Query 2 would block until the first transaction was committed. In REPEATABLE READ mode, the range would not be locked, allowing the record to be inserted and the second execution of Query 1 to include the new row in its results.


隔离级别 对应的隔离级别是幻读级别,幻读级别和重复读是同一个级别,所以对应的隔离级别是repeat read。


怎么解决幻读的问题?

使用范围锁/行锁——在指定范围内不允许插入新的记录。

能解决幻读问题的隔离级别,叫序列化Serializable,就是按顺序执行事务,一个一个来,不能插队。当然不是全部锁住,一下子锁住一张表,而是针对每一个隔离级别出现的问题,锁住对应的数据,比如,行数据,范围数据。在行数据,范围数据,读期间,不允许其他事务更新,直到事务1已经提交。

有哪几种隔离级别

1.读未提交 //

2.读已提交 //
3.重复读 //
4.序列读 //

后果和隔离级别之间的关系

见上文。

数据库的锁

1.行锁

2.范围锁
3.表锁

锁与sql、事务、事务隔离的关系

见上文。

事务隔离的底层实现

先理解读数据的几种问题,再理解如何解决这几种问题,就基本上理解了事务隔离和事务隔离级别。

数据库厂商是怎么实现事务的?

1.事务日志

2.依靠事务日志,记录每一步/每个sql的成功失败状态等信息,从而实现提交和回滚功能。

数据库厂商是怎么实现事务隔离的

mysql

默认隔离级别是重复读。

oracle

默认隔离级别是读已提交。

实战

代码

用户请求——》控制器层——》业务层——》DAO层——》持久层——》数据库。

客户端

mysql默认存储引擎是innodb,innodb默认隔离级别是重复读repeat read。但是,客户端多个选项卡,可以看到未提交数据,为什么?

按理来说,重复2次读的数据一样,都是旧的数据。这是为什么呢,因为客户端的多个选项卡是在同一个连接同一个事务,所以可以看到其他选项卡的未提交更新。

那么如何在客户端打开多个选项卡的时候,是打开多个连接/事务?看客户端文档。

spring事务

要理解spring事务和事务隔离,首先得理解数据库的事务和事务隔离,所以,把spring事务放在数据库事务和事务隔离一起讲比较好。


参考

spring transation章节。


如何配置


如何使用

隔离级别

和数据库的隔离级别是一样的。有4种情况。


哪个类? Isolation枚举类。


怎么配置? 如果是使用基于注解,那么注解类的属性隔离级别就是配置当前方法的隔离级别的。

默认的隔离级别和当前数据库厂商的隔离级别是一样的,比如,oracle是读已提交,mysql是重复读。


怎么使用? 只需要配置就ok了。

传播级别

同上。

参考

1.数据库厂商的官方文档-transation和isolation这2部分。

2.维基百科

转载于:https://juejin.im/post/5c08e23851882509a7683331

你可能感兴趣的文章
Spring源码阅读——3
查看>>
使用ZXing生成可供手机识别的二维码
查看>>
【原创】modb 开发之需求和总体设计
查看>>
mysql explain type连接类型示例
查看>>
统计文件中不小于某一长度的单词的个数(泛型算法实现)
查看>>
常见缓存算法和缓存策略
查看>>
MyBatis学习总结(10)——批量操作
查看>>
新开activity并且新旧窗口之间传值
查看>>
Linux文件系统的几个性能测试软件小结
查看>>
让 Linux Deepin 终端丰富多彩(2)
查看>>
关于大型网站技术演进的思考(一)--存储的瓶颈(1)
查看>>
MFS部署
查看>>
马哥linux作业第一周
查看>>
VC判断网络连接、是否为win7系统、是否为正版Win7
查看>>
Tomcat中容器是什么以及容器与容器之间的数量关系。
查看>>
C# 判断窗口是否打开
查看>>
JCaptcha图片验证,解决区分大小写问题
查看>>
服务器状态监测 Keepalived
查看>>
centos6.5_x64 安装配置java+tomcat+apache
查看>>
【VMCloud云平台】SCCM(八) OSD(三)- 模板机捕获
查看>>