事务 隔离级别 脏读 不可重复 幻读
事务的定义
事务,就是一组操作数据库的动作集合。
如果一组 处理步骤 全部发生或者一步也不执行,我们称该组处理步骤为一个事务。
当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。
由于其中的一部分或多步执行失败,导致没有步骤被提交,则事务必须回滚到最初的系统状态。
二、事务的并发问题
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_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE (默认 REPEATABLE_READ)
Oracle : READ_UNCOMMITTED、READ_COMMITTED、 SERIALIZABLE(默认 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类似的操作。
补充:
1、SQL规范所规定的标准,不同的数据库具体的实现可能会有些差异
2、mysql中默认事务隔离级别是可重复读时并不会锁住读取到的行
3、事务隔离级别为读提交时,写数据只会锁住相应的行
4、事务隔离级别为可重复读时,如果有索引(包括主键索引)的时候,以索引列为条件更新数据,会存在间隙锁间隙锁、行锁、下一键锁的问题,从而锁住一些行;如果没有索引,更新数据时会锁住整张表。
5、事务隔离级别为串行化时,读写数据都会锁住整张表
6、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。