【MySQL】事务 与 锁

阅读更多

事务的 4个 特性(ACID)

  • 原子性(Atomicity):事务是不可分割的工作单元,其包含的操作,要么都做,要么都不做。
  • 一致性(Consistency):事务执行后,数据记录必须符合各项约束条件。
  • 隔离性(Isolation):并发事务的执行不能相互干扰。
  • 持久性(Durability):事务成功提交意味着相关改动已被持久化保存。即使数据库服务中断,也不会丢失以提交事务的改动。

 

事务的 4个 隔离级别

事务的隔离级别用于控制事务的并发执行。MySQL InnoDB提供了 SQL-1992 中定义的4个隔离级别。

可为事务设置隔离级别,以优化事务并发的性能。
可为单个session设置(set transaction),也设置MySQL的默认隔离级别

 

Repeatable Read:可重复读

这是MySQL默认的隔离级别,也是最常用的级别。

在单次事务内,多次执行相同的(非锁)查询操作,所得结果相同。(除非事务内部自己改了数据)

在第一次查询结果返回后,这些结果数据会被做成快照,后续相同的查询将从快照获取结果(MVCC,Multiversion Concurrency Control)。

这种不加锁的模式存在 幻读 问题。

 

Update、Delete、有锁读(Select For Update/Share)操作需要加锁。可防止 幻读。
使用了 唯一索引 查询条件:只锁住索引指向的记录(record lock)。
其它查询条件:会锁住索引记录及受影响的相关区域记录(gap lock,next-key lock)

 

Read Committed:读已提交

非锁读:每次读取都使用一个新建的快照,即使这些读取操作都在同一次事务中(不可重复读)。

Update、Delete、有锁读:只锁住索引指向的记录,允许其它session在受影响的区域插入数据。只有在检查外键和重复建时会使用 间隙锁(gap lock)。

 

因为不对受影响的区域使用 间隙锁(gap lock),其它session插入新数据可能会导致 幻读(Phantom Rows)。

对于 Update 和 Delete,InnoDB只会对被更新或删除的记录加锁,其它未匹配到的记录在Where条件执行结束后就会被释放,所以可大大减小发生死锁的几率

对于 Update,如果真的发生了死锁,InnoDB会尝试“半一致”读取,返回最近被提交的版本,以决定相关记录是否符合当前Update中的Where条件。

 

Oracle的默认事务隔离级别就是 Read Committed。为什么MySQL的是 Repeatable Read?

 

Read Uncommitted:读未提交

这是 最低 的隔离级别。

读取操作不加锁,且允许读取其它事务已更改但未提交的数据脏读)。

其它操作与Read Committed相同,也存在 幻读 问题。

 

Serializable:串行

这是 最高 的隔离级别。

所有事务依次逐个执行(如有必要),完全不会互相干扰。性能也最低。

 

MySQL 中的锁

悲观锁 vs 乐观锁

悲观锁:为避免其它事务意外修改数据,可使用悲观锁。Select ... For Update 这样的语句就可以实现此类效果。
 

乐观锁:使用CAS机制,不对数据加锁。通过比对数据的时间戳或版本号来满足相关版本判断。
 

MVCC(Multiversion Concurrency Control)就是乐观锁。
排他性的读写锁、双阶段锁 都是悲观锁。

 

表级锁(Table-Level Lock)

MySQL中 粒度最大 的锁。对当前操作的整个表加锁。不会出现死锁,并发度低。

MyISAM 采用表级锁。InnoDB 默认使用行级锁,也支持表级锁。

 

行级锁(Row-Level Lock)

MySQL中 粒度最小 的锁。只对当前操作的记录行加锁。并发度高,会出现死锁。

 

InnoDB 中的几种锁类型

InnoDB 实现了多种类型的锁(算法):

  • 共享/排它锁(Shared/Exclusive Lock):共享锁也称为 读锁,用于读取数据;排它锁也称为 写锁,用于更新或删除数据。
  • 记录锁(Record Lock):对具体索引记录的锁。
  • 间隙锁(Gap Lock):对索引区间的锁。
    插入意向锁(Insert Intention Lock)是特殊的间隙锁。
  • Next-Key Lock:记录锁 和 间隙锁 的结合。可以防止幻读。如果查询索引属于唯一索引,会降级为 Record Lock。
  • AUTO-INC Lock:一种特殊的表级锁。用于自增列(Auto_Increment)。
  • 空间索引预言锁(Predicate Locks for Spatial Index):类似 Next-Key Lock,专用于空间索引。因为Next-Key Lock 无法空间索引(多维数据没有绝对的顺序概念),所以为了支持 “可重复读” 和 “串行” 这两个隔离级别,需要此类型的锁。
  • 意向锁(Intention Lock):属于表级锁,包括 意向共享锁(IS)和 意向排它锁(IX),使得InnoDB锁的颗粒度更多样化。

虽然也可以在应用程序端主动使用MySQL的锁方法(Get_Lock、Release_Lock),既降低加锁的开销,又获得所需的一致性,但还是不建议这么做。这种做法维护太复杂,几乎总是得不偿失。
使用类似Spring事务管理框架应该是比较通用流行的方式。

 

 

你可能感兴趣的:(【MySQL】事务 与 锁)