事务的隔离级别

事务具有ACID四大特写

  • 原子性,操作是原子的,要么都成功,要么都不成功
  • 一致性,从一个一致状态到另一个一致状态,不会出现数据不一致的情况
  • 隔离行,事务直接互不影响,数据库提供多种隔离级别
  • 持久性,事务提交后对数据的修改是永久性的

隔离等级

  • 脏读,可能读到未提交的数据
  • 不可重复读,事务中读第二次时,发现数据已经不一样了,主要针对数据的内容,如M的x=100,第二次读变成x=200了
  • 幻读,和不可重复读类似,主要是针对一批数据,如第一次读有3行,第二次读有4行,就出现了幻影行的情况

Mysql支持的隔离级别

  • 串行 避免脏读、不可重复读、幻读
  • 可重复读 避免脏读、不可重复读 (Mysql默认级别,5.5可避免幻读的情况)
  • 读已提交 避免脏读
  • 读未提交 什么都不保证

查看Mysql隔离登记


 	select @@tx_isolation;

	REPEATABLE-READ

隔离级别的实现方式

共享锁(S\读锁)

对数据对象M加S锁,只能进行读操作,不能进行更新操作,只有所以的S锁被释放,才能获取到写锁

排他锁(X\写锁)

对数据对象M加X锁,既可以读M,也可以修改M,期间其他事物不能对M加任何锁

innodb行级锁

采用位图bitmap存储行锁
锁可重用,同一事务多次锁一行

悲观锁

对外接修改持保守态度

乐观锁

采用宽松的加锁机制,基于数据库版本机制:加一个"version"字段,读数据时,将版本号一同读出,version + 1,如果新的version > 目前数据库中的version,则更新,否则认为过期

读到数据后立即加共享锁,直到事务结束才释放锁

丢失更新

由于写锁需要获取锁,在未获取到锁无法get version,当一个事务A对数据M加了写锁,其他事务需先获取锁,事务Acommit后,其他事务才获取到version,因此满足版本控制,同时其他事务的修改,可能覆盖了事务A的修改,这种情况应该由程序控制,select时应该是在事务中的(不是很了解)

Innodb锁

  • Mysql的行锁是针对索引加的锁,如果查询for update,或update时,没有用到索引,innodb将使用表锁

  • 由于行锁是针对索引加的,不是针对记录加的,如果用到了同一个索引键,可能会产生锁冲突

  • 当表有多个索引时,不同事物可以使用不同的索引锁定不同的行

  • 即便使用了索引字段,Mysql在检索时也不一定使用索引,Mysql通过判断不同的执行计划的代价来决定的,例如:索引的记录超过整个表的30%时,会使用全表扫描,而不是索引,因为索引筛选的数据不能提炼出小部分数据

  • 单纯select 不会加锁, 使用select for update强行加锁?

  • Innodb使用间隙锁来对条件范围内不存在的记录加锁,如:Select * from emp where empid > 100 for update;如果表中没有empid大于100的数据,mysql会对这些不存在的记录加锁,来防止其他事务插入大于100的数据,同时也就防止了幻读的发生

一致性读(RR(repeatable-read)情况下)是指select * from a时,使用的是MVCC机制读取undo的已经提交的数据,是非阻塞的,这种情况是不加锁的读,它只对第一条执行的select语句和自身修改的数据敏感,如果需要加锁读,则使用:
Select ... from ... Lock in share mode
Select * from ... For update
事务的开始并非是begion,而是第一条sql

当前读(current read) ,是指update, delete, select for update, select in share mode等等语句进行的读,它们读取的是数据库中的最新的数据,并且会锁住读取的行和gap(RR隔离时)。如果不能获得锁,则会一直等待,直到获得或者超时

posted on 2018-01-09 15:56  j.liu windliu  阅读(243)  评论(0编辑  收藏  举报