数据库事务的隔离级别

1.什么是事务

事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。事务是恢复和并发控制的基本单位。

2.事务的特性(ACID)

  1. 原子性(atomicity):一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。
  2. 一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性密切相关的。
  3. 隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  4. 持久性(durability):一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

3.事务需要解决的问题

1. 脏读
脏读指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据,这就是脏读。

2. 不可重复读
不可重复读指的是在同一事务内,不同的时刻读到的同一批数据可能是不一样的,可能会受到其他事务的影响,比如其他事务改了这批数据并提交了。
3. 幻读
事务A 按照一定条件进行数据读取, 期间事务B 插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取时,发现了事务B 新插入的数据 称为幻读。(insert操作)

4.事务的隔离级别

  1. 读未提交(READ UNCOMMITTED):可以读到其他事务未提交的数据。
  2. 读提交(READ COMMITTED): 读已提交是通过快照读的方式来读取数据,事务里的,每一次select 都重新创建一份快照,所以无法解决不可重复读。(oracle和sql serve默认的事务隔离级别)
  3. 可重复读 (REPEATABLE READ):。可重复读也是采用快照读的方式,只不过它产生快照是在第一次查询的时候创建,整个事务都用的同一份。同一事务内的update操作可以被读到,其他事务在select操作之前提交,可以被读到。mysql下面事务可重复读解决了幻读(见下面read view)
  4. 串行化 (SERIALIZABLE):事务串行化顺序执行。对于同一行记录,“写”会加“写锁”,“读”会加“读锁”,当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。采用当前读就,即永远读最新的版本的数据。

从上往下,隔离强度逐渐增强,性能逐渐变差。MySql中InnoDB才支持事务,MyISAM不支持事务

隔离级别 脏读 不可重复读 幻读
读未提交 × × ×
读提交 × ×
可重复读
序列化

在 InnoDB 中的可重复读不存在幻读问题,对于快照读,InnoDB 使用 MVCC 解决幻读,对于当前读,InnoDB 通过 gap locks 或 next-key locks 解决幻读
注:√代表解决

5.当前读和快照读

5.1当前读

当前读读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。例如:select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读。

5.2快照读

快照读即不加锁的非阻塞读。快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读。之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC。即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本

6.MVCC(多版本的并发控制)

6.1概述

MVCC使得数据库读不会对数据加锁,普通的SELECT请求不会加锁,提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。借助MVCC,数据库可以实现READ COMMITTED,REPEATABLE READ等隔离级别。实现原理主要是依赖记录中的 隐式字段,undo日志 ,Read View 来实现的。

6.2隐式字段

  • DB_TRX_ID(6byte)
    最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID

  • DB_ROLL_PTR(7byte)
    回滚指针,指向这条记录的上一个版本(存储于rollback segment里)

  • DB_ROW_ID(6byte)
    隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引

6.3undo日志

  • insert undo log
    代表事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃

  • update undo log
    事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除, 只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除

6.4Read View(读视图即快照读)

  • 如果被访问版本的 trx_id (事务id)属性值小于 m_ids 列表(在生成ReadView时当前系统中活跃的读写事务的事务id列表)中最小的事务id,表明生成该版本的事务在生成 ReadView 前已经提交,所以该版本可以被当前事务访问。

  • 如果被访问版本的 trx_id 属性值大于 m_ids 列表中最大的事务id,表明生成该版本的事务在生成 ReadView 后才生成,所以该版本不可以被当前事务访问。

  • 如果被访问版本的 trx_id 属性值在 m_ids 列表中最大的事务id和最小事务id之间,那就需要判断一下 trx_id 属性值是不是在 m_ids 列表中,如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,m_ids 列表中比它大的事务id,该版本可以被访问。

  • 如果被访问版本的trx_id属性值与ReadView中的creator_trx_id(生成该ReadView的快照读操作产生的事务id)值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。

你可能感兴趣的:(数据库,mysql,java)