数据库技术专题

MySQL-InnoDB事务隔离级别和锁机制

2018-10-26  本文已影响178人  agile4j

作者:刘仁鹏
参考资料:

  1. 《MySQL技术内幕 InnoDB存储引擎》
  2. MySQL的并发控制与加锁分析

1.基础知识

1.索引

1.聚集索引

2.辅助索引

扩展:在SQLServer数据库中,并不使用索引组织表,而是使用一种称为堆表的表类型。因此对于SQLServer来说,书签是一个行标识符,用类似 文件号:页号:槽号 的格式来定位行数据。

2.锁机制

1.记录锁

  1. 共享锁(S Lock):允许事务读一行数据。
  2. 排它锁(X Lock):允许事务删除或更新一行数据。

2.范围锁

  1. Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。
  2. Next-Key Lock:Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身。

3.多粒度锁

  1. 意向共享锁(IS Lock):事务想要获得一张表中某几行的共享锁。
  2. 意向排它锁(IX Lock):事务想要获得一张表中某几行的排它锁。

3.并发控制协议

1.MVCC

注意:不同事务隔离级别下,快照读对历史版本的读取方式并不相同:read committed级别下,对快照数据总是读取 最新一份的 快照数据;repeatable read级别下,总是读取当前 事务开始时的 快照数据。

2.LBCC

// 读加S锁
select * from table where ? lock in share mode;

// 读加X锁
select * from table where ? for update;

// 写加X锁
所有的DML操作:insert, update, delete 

4.并发问题

1.脏读

2.不可重复读

3.幻读

2.事务隔离级别

1.read uncommitted

2.read committed

3.repeatable read

4.seraliable

3.SQL加锁分析

delete from t1 where id=10;

1.id列是主键,RC隔离级别

2.id列是辅助唯一索引,RC隔离级别

3.id列是辅助非唯一索引,RC隔离级别

4.id列上没有索引,RC隔离级别

组合4.jpg-72.1kB组合4.jpg-72.1kB

5.id列是主键,RR隔离级别

6.id列是辅助唯一索引,RR隔离级别

7.id列是辅助非唯一索引,RR隔离级别

8.id列上没有索引,RR隔离级别

9.Serializable隔离级别

4.错误案例分析

1.先读后更新导致的线程安全问题

public Long getNum(Long templateId) throws Exception {
       beginTransaction();
       try {
           ContractCodeState numInfo = stateDao.searchByTemplateId(templateId);
           numInfo.setNum(numInfo.getNum + 1);
           stateDao.update(numInfo);
           commitTransaction();
           return numInfo.getNum();
       } catch (Exception e) {
           rollbackTransaction();
           throw e;
       }
}
public Long getNum(Long templateId) throws Exception {
       beginTransaction();
       try {
           stateDao.incrementNum(templateId);
           ContractCodeState numInfo = stateDao.searchByTemplateId(templateId);
           commitTransaction();
           return numInfo.getNum();
       } catch (Exception e) {
           rollbackTransaction();
           throw e;
       }
   }

下拉查看答案:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

会发生死锁。InnoDB检测到死锁后,会回滚其中一个事务,使另一个事务成功执行完毕。即并发请求时,只有一个请求可成功执行,而另一个事务将回滚,并返回异常。如下图:
1).事务1阻塞。


pic1.png-686.1kBpic1.png-686.1kB

2).死锁。事务1执行成功,事务2自动回滚并返回异常。


pic2.png-770.1kBpic2.png-770.1kB
  1. serializable隔离级别并不是完全串行化,而是读写串行化
  2. 尽量避免先读后更情况的发生,转为先更后读
  3. 如果一定要先读后更,那么可以使用加X锁的一致性锁定读(for update)。

end

上一篇 下一篇

猜你喜欢

热点阅读