事务 隔离级别 脏读 不可重复 幻读

 

 事务的定义

事务,就是一组操作数据库的动作集合。

如果一组 处理步骤 全部发生或者一步也不执行,我们称该组处理步骤为一个事务。

当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。

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

二、事务的并发问题

1、脏读:事务A读取了事务B更新、未提交的数据,然后B回滚操作,那么A读取到的数据是脏数据(没有用的数据)

2、不可重复读:事务 A 多次读取同一数据,结果读取的数据不一致,也就是说不支持重复读,重复读会有错误。      原因是 事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据不一致。

3幻读:事务A读取所有工资为5000的人数为10人。此时,事务B插入一条工资也为5000的记录。这,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。  需要表锁才能隔离,所以大都数数据库都 没有将幻读隔离。

  小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

 

三、MySQL事务隔离级别

事务 隔离级别 脏读 不可重复 幻读

事务隔离级别

读取速度

脏读

不可重复读

幻读

含义

读未提交(read-uncommitted

效率高,

但是不用

允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读

不可重复读级别的read-committed

orcale

采用的级别

允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生

可重复读(repeatable-read

mysql

的级别

对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。

串行化(serializable

隔离级别最高

 

安全,效率最低

完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。



 事务的隔离级别 ,是由数据库提供的 ,并不是所有数据库都支持四种隔离级别

       MySQL : READ_UNCOMMITTEDREAD_COMMITTEDREPEATABLE_READSERIALIZABLE (默认 REPEATABLE_READ

       Oracle READ_UNCOMMITTEDREAD_COMMITTEDSERIALIZABLE(默认 READ_COMMITTED

查询当前级别 mysql>select @@tx_isolation


spring五种隔离级别

第一种是默认的,ISOLATION_DEFAULT  使用数据库默认的事务隔离级别. 另外四个与JDBC的隔离级别相对应;

第二种是ISOLATION_READ_UNCOMMITED, 会产生脏读, 不可重复读, 幻读

第三种是ISOLATION_READ_COMMITED, 可以防止脏读, 但是会发生不可重复读和幻读

第四种是ISOLATION_REPEATABLE_READ, 可以防止脏读和不可重复度, 但是会产生幻读

第五种是ISOLATION_SERIALIZABLE,spring事物的最高隔离级别, 可以防止脏读,不可重复读, 幻读的发生, 但是这种隔离级别极大的牺牲了性能.

 

其中spring七个事物传播属性:
PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,
则进行与PROPAGATION_REQUIRED类似的操作。

 


补充:

1SQL规范所规定的标准,不同的数据库具体的实现可能会有些差异

2mysql中默认事务隔离级别是可重复读时并不会锁住读取到的行

3、事务隔离级别为读提交时,写数据只会锁住相应的行

4、事务隔离级别为可重复读时,如果有索引(包括主键索引)的时候,以索引列为条件更新数据,会存在间隙锁间隙锁、行锁、下一键锁的问题,从而锁住一些行;如果没有索引,更新数据时会锁住整张表。

5、事务隔离级别为串行化时,读写数据都会锁住整张表

6、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。