事务的特性

关于 ACID

https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_acid

  • 原子性(atomic):原子操作主要体现在 对于一个事务开启后,后续操作中肯定存在事务回滚或提交两种操作,体现了 synchronize-relation 关系
  • 隔离性(isolation):不同事务之间的操作动作本身不会存在影响,但由于不同的事务隔离级别从结果层面体现可能不同的事务之间操作并未完全隔离
  • 一致性(consistency):对于同一个事务中的不同的操作, 其结果只能是操作共同成功且事务成功提交或存在操作失败,事务统一回滚; 不可能出现同一个事务中 不同的操作结果,事务却正常提交
  • 持久性(durability):对于已成功提交的事务,不支持回滚操作

 

mysql innodb 引擎下默认事务隔离级别为 repeatableRead

mysql中存在的事务隔离级别类型 : https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html

序列化(顺序性) : https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_serializable

重复读 : https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_repeatable_read

读已提交 : https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_read_committed

读未提交 : https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_read_uncommitted

mysql 事务隔离级别包含(按照从低到高顺序)

  • readUncommited : 读未提交 
  • 对于当前事务级别基本属于free_lock状态,对于当前事务存在脏读问题的发生,因此通常建议在使用当前隔离级别时,只允许读操作
  • readCommit (consistent read): 读已提交
  • 为了提高性能,在当前事务隔离级别下锁降低了对事务之间的保护措施;对于同一个事务,其不能读取到事务未提交的数据,但允许读取到并行阶段已提交事务的数据(当前情况就是并行事务下的unrepeatable-read问题);但即使对于读取到已提交的数据也依赖于其他事务的提交时间
  • 在当前隔离界别下存在不同的锁操作
  • update..where 加锁操作并会阻塞其他事务
  • delete..where 加锁操作并会阻塞其他事务
  • select .. where..for update 加锁操作但并不会阻塞其他事务
  • select .. where in share mode 加锁操作但并不会阻塞其他事务
  • repetableRead : 重复读 ;
  • 在重复读隔离级别下避免了 non-repeatableread 问题的发生,但并不能避免幻象(phantom)操作;
  • 对于保证non-repeatableread的操作,对于读取操作在事务开启情况下,会先生成一份快照数据,在同一个事务中后续的读取操作实际都是读取的快照数据,因此可以保证同一个事务中的读取操作的consistent
  • repeatable-read 实际也利用到了锁,当相对于 serializable 级别下的表锁,其利用了相对温和的锁操作;以下操作会开启锁,并会阻止其他事务操作
  • update..where
  • delete..where
  • select..where ..for update
  • select .. where .. lock in share mode; 在5.8中 使用了 select .. where .. for share替代了当前操作,但lock in share mode操作也是支持的
  • serializable : 序列化 ;
  • 当前隔离级别采用最保守的锁策略(表锁(lock table)),对于一个事务即使是执行读取操作也会对表进行加锁,从而禁止了其他事务在当前持有表锁事务尚未结束前操作表;
  • 对于当前已持有的锁的事务具有可重入(reentrant)的特性,即在同一个事务(已持有锁,且事务未提交前)中可以重复执行读取操作,不需要再次重新获取锁;因此对于同一个事务的读取操作其保证了一致性;
  • 但由于表锁过于悲观,以及性能太差,因此mysql innodb 引擎的默认事务隔离级别为 repeatable read

mysql 官方相关定义

脏读:https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_dirty_read

幻象: https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_phantom

不可重复读:https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_non_repeatable_read

并发事务下可能出现的事务问题

  • 脏读(dirty read) : 脏读实际只会发生在 readUncommitted事务隔离级别下,当前操作实际表现的是读到了不可靠(事务未提交)的数据; 事务存在持久性(durability) 的特性,已提交的数据是不可逆的;但对于事务未提交的数据,由于在事务提交之前也可以对数据进行修改,也有可能发生事务回滚(rollback); 举例: A事务先执行数据读取操作;此时B事务执行数据写入操作,但事务未提交,此时A事务再次读取数据时,此时A读到了B事务未提交事务的数据;B事务回滚,对于B事务相关数据操作并不会实际存储到数据库中;此时A事务实际就是读取到了一个实际并不存在的数据
  • 幻象(phantom) : 幻象和脏读的区别点在于,幻象中的读取操作-幻读是读取到了并发事务中已提交事务(可靠)的数据,对于幻读操作只有在serializable隔离级别下才不会发生,原因是在当前事务隔离级别下,事务的所有操作都是表锁,因此不存在所谓的并发事务,也就不会出现幻读的问题;对于其他事务隔离级别下均会发生;幻象操作 实际涵盖了读写所有的操作,不仅仅是读取操作; 
  • 不可重复读(non-repeatable read) : 在同一个事务中多次相同条件读取到的结果不同,读取到其他事务已提交的数据;其操作实际违反了ACID中的consistency(一致性);对于当前操作在serializable和repeatable read 事务隔离级别下不会发生,但在readUncommitted 和 consistent read级别下还是会存在的