数据库事务Transaction有四大特点:ACID
本文主要介绍一下Isolation隔离性。
什么是事务
第一篇介绍原子性的文章里,我们还没有涉及太多事务,讲到隔离性,不妨先简单介绍下什么是事务。
一个数据库事务通常包含对数据库进行读或写的一个操作序列。它的存在包含以下两个目的:
1. 为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
2. 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
以下是一个简单的使用事务的例子:
mysql> CREATE TABLE test( id int(5)); # 创建数据表
Query OK, 0 rows affected (0.04 sec)
mysql> select * from test;
Empty set (0.01 sec)
mysql> begin; # 开始事务
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test value(5);
Query OK, 1 rows affected (0.01 sec)
mysql> insert into test value(6);
Query OK, 1 rows affected (0.00 sec)
mysql> commit; # 提交事务
Query OK, 0 rows affected (0.01 sec)
什么是隔离性
数据库是一个并发系统,可以同时处理不同客户端的请求,如何解决不同客户端之间的读写冲突和写写冲突? 一种简单的做法就是让所有操作都串行化执行,这样可以100%保证数据正确性,但是吞吐量会急剧下降。
然而,大部分业务场景不需要100%保证正确性,但是需要比较高的吞吐量。 隔离性提供了一种在正确性和吞吐量之间的权衡方法, 使用不同的隔离级别可以使数据库使用者在正确性和吞吐量之间做权衡:
ANSI/ISO SQL-92中定义了四种隔离级别:
1. READ UNCOMMITTED
2. READ COMMITTED
3. REPEATABLE READ
4. SERIALIZABLE
同时定义了三种异常现象,来具体阐述每种隔离级别的区别:
1. Dirty Read 脏读
2. Non-repeatable Read 不可重复读
3. Phantom Read 幻读
假设事务T1修改了一个数据,事务T2在T1 COMMIT(提交修改)或ROLLBACK(撤回修改)前读取了该数据, 如果T1最终执行ROLLBACK,T2将会读到一个不存在的数据。
假设事务T1先读取了一个数据,之后事务T2删除或者修改了这个数据并且COMMIT,如果T1再次读取这个数据, 将会读不到该数据,或者读到一个修改过的数据。
事务T1读取了一些满足某个条件的数据,事务T2插入了满足这个条件的一些新数据并且COMMIT, 如果T1再次尝试读取满足同一个条件的数据,将会读到和第一次不一样的数据,T2插入的数据也会出现在结果中。
ANSI/ISO SQL-92通过是否会发生以上三种异常现象来定义这四个隔离级别,如下表:
HelloMin: 简单说下我的理解:SERIALIZABLE,以上三种现象都不会发生,对同一个数据库同一时刻仿佛只会有一个事务在运行,不会出现在一个事务中不同时刻读到不同数据的问题。
重点说一下仿佛:在SERIALIZABLE的定义中,没有强制要求一定要读写阻塞,只是说能达到互不影响的效果就可以,至于具体实现的时候是真的一个事务一个事务串行执行,还是并发执行但是避免了异常,这取决于具体的实现。之后Mars会写一下隔离级别的几种实现,我已经先讨教过了,确认可以有很多玩法,不一定非要加锁。
REPEATABLE READ,有可能会出现用同一种读取标准,第二次读到的数据比第一次读到的数据多了一些新的数据,但是可以保证事务中已经读到的数据都是不会被别人删除修改的。
READ COMMITTED,只能保证读到的数据都是别的事务成功提交的,但是在事务过程中,读到的数据可能被删改,也可能出现新的数据。
READ UNCOMMITTED,这个基本就是各种不保证了,只要有别人也在改数据,读到什么都是可能的。
TiDB 实现了其中的两种:可重复读和读已提交。
1. 可重复读
可重复读是 TiDB 的默认隔离级别,当事务隔离级别为可重复读时,只能读到该事务启动时已经提交的其他事务修改的数据,未提交的数据或在事务启动后其他事务提交的数据是不可见的。对于本事务而言,事务语句可以看到之前的语句做出的修改。
尽管名称是可重复读隔离级别,但是 TiDB 中可重复读隔离级别和 ANSI 可重复隔离级别是不同的,TiDB 实现的是论文中的snapshot隔离级别,该隔离级别不会出现幻读,但是会出现写偏斜,而ANSI可重复读隔离级别不会出现写偏斜,会出现幻读。
读已提交隔离级别和可重复读隔离级别不同,它仅仅保证不能读到未提交事务的数据,需要注意的是,事务提交是一个动态的过程,因此读已提交隔离级别可能读到某个事务部分提交的数据。
不推荐在有严格一致要求的数据库中使用读已提交隔离级别。
以上就是本期的直男Mars讲数据库系列了,文中提到的各种隔离级别分别可以有什么实现的方式,以及所谓的写偏斜是什么,我们下次再续!
文中提到的论文链接,微信不让放其他域名的超链接,有兴趣的同学复制粘贴到浏览器查看:
https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-95-51.pdf
Schönes Wochenende!
我的2019周更计划已完成:25/52
[********............]
本文分享自 Pair Programming 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!