数据库事务,是一组独立的逻辑操作,组成这组操作的单元,不成功便成仁,颇有武侠小说里的江湖豪情。因其独特的品质,被广泛应用在订单系统和银行系统等应用场景。似乎看起来有些模糊,一起来看一个简单的例子。
小采风同学节衣缩食,终于凑齐了一直拖欠小楠同学的500元人民币,兴高采烈得还钱去。这里有两个简单的操作,小采风账目减少500元,小楠同学账目增加500元,一切皆大欢喜。可是,如果支付宝系统,在小采风账目减少500元的同时,后台的数据库系统宕机,自己减少了500元,小楠同学的账目并没有增加500元,我说钱已经偿还过了,不信你看余额?小楠同学委屈到,没有,我这没有任何记录?难道昔日纯洁的革命友谊,因此便灰飞烟灭了吗?
为什么我们生活中没有这样的案例呢?因为数据库事务的存在。它要求一组操作,要么全部成功,要么全部失败。让我们一步步揭开数据库事务的神奇面纱吧!
一、事务的ACID特性
1、A(atomicity) 原子性:一个事务的执行被视为不可分割的最小单元,要么全部成功,要么全部失败,不能只执行其中的一部分;
2、C(consistency) 一致性:一个事务的执行不能破坏数据库完整性约束,上面案例中小采风和小楠同学的转账操作中,账目总金额不能发生变化;
3、I(isolation) 隔离性:数据库为每个用户开启的事务应该不能相互干扰,并发事务之间无相互影响,当然事务之间有相互关系,其隔离性由下文分析;
4、D(durability) 持久性:事务提交之后,提交后的数据持久化到硬盘上;
Mysql数据库事务有三个命令,transaction用于开启事务,rollback用于回退,commit用于提交。四个基本特性,原子性、一致性和持久性由事务日志实现,隔离性由锁实现。下面让我们来看一看事务的隔离性;
二、事务的隔离性
隔离性,是指多个事务之间的相互关系。如果不考虑隔离性,可能会引发下面问题:
1、脏读:一个事务读取另一个事务未提交数据
故事背景:
小采风:小楠同学,我已经开启转账事务,向你转账500元,你查收一下。
小楠:嗯,我已经开启查询事务,看到转账了,你这孩子,再不还钱,就不和你玩了(心理一通抱怨)。
小采风:你已经看到转账了是吗?我们已经两清了,可以一起开心的玩耍了。(此时,默默开启了回退业务,并未提交)
小楠:咦?刚刚到账的500元怎么忽然没有了呢?难道刚刚是在做梦?
案例解读:
此现象属于脏读情况,即小楠同学的查询事务,读取了小采风同学的未被提交的转账业务,所以小楠同学可以放心找小采风同学理赔了。
2、不可重复读:读取前一事务提交的数据
故事背景:
银行正在读取小采风的账户余额,初次查询后为500元,此时心存愧疚的小采风,悄悄的开启转账业务,将500元成功转账给小楠同学,方便其顺利度过双十一。此时银行再次读取小采风账户余额,突然之间余额为0。当然,需要一后者为准。但是银行程序需要将查询结果分别输出到电脑屏幕和写到文件中,结果在一个事务中针对输出的目的地,进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作人员就尴尬了。
案例解读:
此现象是银行查询事务读取前一事务已提交的数据,导致多次查询结果不一致。
3、虚读:读取其他事务插入的数据
故事背景:
小楠:双十一的日子快到了,我得开启查询事务,看一看账户还有多少钱?天呐?88元,看来双十一只能说拜拜了。(一阵叹息,但是查询业务并未关闭)
小采风:上次莫名开启回退业务,简直是于心不忍,心中无比愧疚,怎么能这样子呢?悄悄开启了转账业务,向小楠同学转账500元,并成功提交。(转账业务开启,并成功提交)
小楠:奇怪了?怎么账户上面突然多了500元钱,这是哪位好心的哥哥,为什么?(未关闭的查询业务读取新的数据)
案例解读:
此现象属于虚读,即读取其他事务插入的数据,小楠同学读取了小采风同学提交的转账金额,导致两次账户余额查询不一致。
针对不同的业务场景,需要采用的隔离措施是不同的,具体来看一看隔离级别:
三、事务的隔离级别
1、READ UNCOMMITTED(未提交读)。在RU的隔离级别下,事务A对数据做的修改,即使没有提交,对于事务B来说也是可见的,这种问题叫脏读。如上面案例中小楠读取小采风未提交的事务;
2、READCOMMITTED(提交读)。在RC的隔离级别下,不会出现脏读的问题。事务A对数据做的修改,提交之后会对事务B可见,举例,事务B开启时读到数据1,接下来事务A开启,把这个数据改成2,提交,B再次读取这个数据,会读到最新的数据2。在RC的隔离级别下,会出现不可重复读的问题。这个隔离级别是许多数据库的默认隔离级别。
3、REPEATABLEREAD(可重复读)。在RR的隔离级别下,不会出现不可重复读的问题。事务A对数据做的修改,提交之后,对于先于事务A开启的事务是不可见的。举例,事务B开启时读到数据1,接下来事务A开启,把这个数据改成2,提交,B再次读取这个数据,仍然只能读到1。在RR的隔离级别下,会出现幻读的问题。幻读的意思是,当某个事务在读取某个范围内的值的时候,另外一个事务在这个范围内插入了新记录,那么之前的事务再次读取这个范围的值,会读取到新插入的数据,如上面案例中小楠双十一的500元惊喜。
4、SERIALIZABLE(可串行化)。可串行化是最高的隔离级别。这种隔离级别强制要求所有事物串行执行,在这种隔离级别下,读取的每行数据都加锁,会导致大量的锁征用问题,性能最差。
小采风的小聪明,终究只是一场闹剧。小楠同学不要见怪哦。数据库的事务,是数据库中比较重要的概念,希望各位看官能有所收获。