事务的特性,事务的隔离级别和传播行为,为何要有隔离级别

事务(Transaction)概念:一个sql语句就是一个事务,事务能够保证一组sql语句要么都成功,要么都失败。spring

事务,就是一组操做数据库的动做集合。事务是现代数据库理论中的核心概念之一。sql

若是一组处理步骤或者所有发生或者一步也不执行,咱们称该组处理步骤为一个事务。数据库

当全部的步骤像一个操做同样被完整地执行,咱们称该事务被提交。并发

因为其中的一部分或多步执行失败,致使没有步骤被提交,则事务必须回滚到最初的系统状态。高并发

特性性能

1. 原子性:一个事务中的全部语句,应该作到:要么全执行要么一个都不执行;spa

2. 一致性:让数据保持逻辑上的合理性。好比一个商品出库时,既要让商品库中的该商品数量减一,又要让对应用户的购物车中的该商品加一;blog

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

3. 隔离性:若是多个事务同时并发执行,但每一个事务就像各自独立执行同样。在事物正确提交以前,不容许把事物对该数据的改变提供给任何其余事物,即在事物正确提交以前,它可能的结果不该该显示给其余事物。内存

4. 持久性:一个事务执行成功,则对数据来讲,应该是一个明确的硬盘数据更改(而不只仅是内存中的变化)

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

做用

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

并发下事物会产生的问题

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

一、脏读

所谓脏读,就是指事物A读到了事物B尚未提交的数据,好比银行取钱,事物A开启事物,此时切换到事物B,事物B开启事物-->取走100元,此时切换回事物A,事物A读取的确定是数据库里面的原始数据,由于事物B取走了100块钱,并无提交,数据库里面的帐务余额确定仍是原始余额,这就是脏读。

二、不可重复读

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

三、幻读

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

为何要有隔离级别

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

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

一、DEFAULT

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

二、READ_UNCOMMITTED

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

三、READ_COMMITED

读已提交,即可以读到那些已经提交的数据,天然可以防止脏读,可是没法限制不可重复读和幻读

四、REPEATABLE_READ

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

五、SERLALIZABLE

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

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


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

spring七个事务传播属性

1.PROPAGATION_REQUIRED – 支持当前事务,若是当前没有事务,就新建一个事务。这是最多见的选择。

2.PROPAGATION_SUPPORTS – 支持当前事务,若是当前没有事务,就以非事务方式执行。

3.PROPAGATION_MANDATORY – 支持当前事务,若是当前没有事务,就抛出异常。

4.PROPAGATION_REQUIRES_NEW – 新建事务,若是当前存在事务,把当前事务挂起。

5.PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操做,若是当前存在事务,就把当前事务挂起。

6.PROPAGATION_NEVER – 以非事务方式执行,若是当前存在事务,则抛出异常。

7.PROPAGATION_NESTED – 若是当前存在事务,则在嵌套事务内执行。若是当前没有事务,则进行与PROPAGATION_REQUIRED相似的操做。

备注:经常使用的两个事务传播属性是1和4,即PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW

关键词:

1)虚读(幻读):在一个事务内读取了别的事务插入的数据,致使先后读取不一致(insert),事务1读取记录时事务2增长了记录并提交,事务1再次读取时能够看到事务2新增的记录;

2)不可重复读取:在一个事务内读取表中的某一行数据,屡次读取结果不一样.一个事务读取到了另外一个事务提交后的数据.事务1读取记录时,事务2更新了记录并提交,事务1再次读取时能够看到事务2修改后的记录;

3)脏读:指一个事务读取了一个未提交事务的数据事务1更新了记录,但没有提交,事务2读取了更新后的行,而后事务T1回滚,如今T2读取无效。