什么是事物

事物是访问数据库的一个操作序列,数据库应用系统通过事物集来完成对数据库的存取。事物的正确执行使得数据库从一种状态转换为另一种状态

事物必须服从ISO/IEC所制定的ACID原则。ACID是原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)的缩写,这四种状态的意思是:

1、原子性

即不可分割,事物要么全部被执行,要么全部不执行。如果事物的所有子事物全部提交成功,则所有的数据库操作被提交,数据库状态发生变化;如果有子事物失败,则其他子事物的数据库操作被回滚,即数据库回到事物执行前的状态,不会发生状态转换

2、一致性

事物的执行使得数据库从一种正确状态转换成另外一种正确状态

3、隔离性

在事物正确提交之前,不允许把事物对该数据的改变提供给任何其他事物,即在事物正确提交之前,它可能的结果不应该显示给其他事物

4、持久性

事物正确提交之后,其结果将永远保存在数据库之中,即使在事物提交之后有了其他故障,事物的处理结果也会得到保存

 

事物的作用

事物管理对于企业级应用而言至关重要,它保证了用户的每一次操作都是可靠的,即便 出现了异常的访问情况,也不至于破坏后台数据的完整性。就像银行的自动提款机ATM,通常ATM都可以正常为客户服务,但是也难免遇到操作过程中及其突然 出故障的情况,此时,事物就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过ATM机一样,以保证用户和银行的利益都不受损失。

 

并发下事物会产生的问题

举个例子,事物A和事物B操纵的是同一个资源,事物A有若干个子事物,事物B也有 若干个子事物,事物A和事物B在高并发的情况下,会出现各种各样的问题。"各种各样的问题",总结一下主要就是五种:第一类丢失更新、第二类丢失更新、脏 读、不可重复读、幻读。五种之中,第一类丢失更新、第二类丢失更新不重要,不讲了,讲一下脏读、不可重复读和幻读。

1、脏读

所谓脏读,就是指事物A读到了事物B还没有提交的数据,比如银行取钱,事物A开启事物,此时切换到事物B,事物B开启事物-->取走100元,此时切换回事物A,事物A读取的肯定是数据库里面的原始数据,因为事物B取走了100块钱,并没有提交,数据库里面的账务余额肯定还是原始余额,这就是脏读。

2、不可重复读

所谓不可重复读,就是指在一个事物里面读取了两次某个数据,读出来的数据不一致。 还是以银行取钱为例,事物A开启事物-->查出银行卡余额为1000元,此时切换到事物B事物B开启事物-->事物B取走100元 -->提交,数据库里面余额变为900元,此时切换回事物A,事物A再查一次查出账户余额为900元,这样对事物A而言,在同一个事物内两次读取账 户余额数据不一致,这就是不可重复读。

3、幻读

所谓幻读,就是指在一个事物里面的操作中发现了未被操作的数据。 比如学生信息,事物A开启事物-->修改所有学生当天签到状况为false,此时切换到事物B,事物B开启事物-->事物B插入了一条学生数 据,此时切换回事物A,事物A提交的时候发现了一条自己没有修改过的数据,这就是幻读,就好像发生了幻觉一样。幻读出现的前提是并发的事物中有事物发生了 插入、删除操作。

 

事物隔离级别

事物隔离级别,就是为了解决上面几种问题而诞生的。为什么要有事物隔离级别,因为事物隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大,因此很多时候必须在并发性和性能之间做一个权衡。所以设立了几种事物隔离级别,以便让不同的项目可以根据自己项目的并发情况选择合适的事物隔离级别,对于在事物隔离级别之外会产生的并发问题,在代码中做补偿。

事物隔离级别有4种,但是像Spring会提供给用户5种,来看一下:

1、DEFAULT

默认隔离级别,每种数据库支持的事物隔离级别不一样,如果Spring配置事物时将isolation设置为这个值的话,那么将使用底层数据库的默认事物隔离级别。顺便说一句,如果使用的MySQL,可以使用"select @@tx_isolation"来查看默认的事物隔离级别

2、READ_UNCOMMITTED

读未提交,即能够读取到没有被提交的数据,所以很明显这个级别的隔离机制无法解决脏读、不可重复读、幻读中的任何一种,因此很少使用

3、READ_COMMITED

读已提交,即能够读到那些已经提交的数据,自然能够防止脏读,但是无法限制不可重复读和幻读

4、REPEATABLE_READ

重复读取,即在数据读出来之后加锁,类似"select * from XXX for update",明确数据读取出来就是为了更新用的,所以要加一把锁,防止别人修改它。REPEATABLE_READ的意思也类似,读取了一条数据,这 个事物不结束,别的事物就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决

5、SERLALIZABLE

串行化,最高的事物隔离级别,不管多少事物,挨个运行完一个事物的所有子事物之后才可以执行另外一个事物里面的所有子事物,这样就解决了脏读、不可重复读和幻读的问题了

网上专门有图用表格的形式列出了事物隔离级别解决的并发问题:

事物隔离级别 脏读幻读 mysql 事物隔离的级别_数据库

再必须强调一遍,不是事物隔离级别设置得越高越好,事物隔离级别设置得越高,意味 着势必要花手段去加锁用以保证事物的正确性,那么效率就要降低,因此实际开发中往往要在效率和并发正确性之间做一个取舍,一般情况下会设置为 READ_COMMITED,此时避免了脏读,并发性也还不错,之后再通过一些别的手段去解决不可重复读和幻读的问题就好了。