mysql架构

  • mysql 事务,锁,隔离机制-LMLPHP

  • 为了解并发问题,引入锁,mysql中锁分为读锁和写锁,即share lock和exclusive lock。故名思义,share lock之间不互斥,share lock和exclusive lock之间互斥,exclusive lock之间互斥。mysql 提供行锁row lock和表锁 table lock的multiple granularity locking。对于表锁,mysql提供一种意图锁的机制,意图锁也是分为两种,intention share lock和intention exclusive lock。对于intention lock
    • Before a transaction can acquire a shared lock on a row in a table, it must first acquire an IS lock or stronger on the table.
    • Before a transaction can acquire an exclusive lock on a row in a table, it must first acquire an IX lock on the table.
    • Intention locks do not block anything except full table requests (for example, LOCK TABLES ... WRITE). The main purpose of intention locks is to show that someone is locking a row, or going to lock a row in the table
    • intention lock之间并不互斥,intention lock只是告诉你有人对表中的某些行在上锁。
  • mysql row lock是在存储引擎层实现的,不同的存储引擎可能有不同的实现方式

事务

  • 事务是指一批操作,要么全部成功,要么全部失败。
  • 数据库事务的ACID特性
    • atomicity原子性:即一个事务已一个原子的操作执行,是一个不可分隔的最小单元,事务中的操作,要么全部执行成功,要么全部失败。
    • consistency 一致性:数据库总是从一个一致的状态转移到另一个一致的状态
    • isolation: 隔离性:一个事务中的修改,在什么时候对另一个事务可见
    • durability: 持久性: 提交的事务不会丢失
  • 隔离级别
  • 隔离级别是对不同的事务而言的。
    • read uncommitted:一个事务中未提交的修改也对另外的事务可见,在这里隔离级别下,会出现脏读,即事务1未提交的修改可能被别的事务可见。
    • read committed: 一个事务提交commit后的修改才对另一个事务可见。但是可能会出现不可重复读的问题,即在一个事务1中,连续select两次,得到的结果不同,因为在这中间,可能记录被别的事务修改了。
    • repeatable read:一个事务中,多次select的结果总是相同的,但可能出现幻读的情况,即虽然对于同一行的结果,始终是相同的,但可能别的事务在insert别的行,导致一个事务中间看到的记录是不同的。
    • serializable:事务串行执行。
  • 怎么解决不可重复读问题?在一个事务开始时,对涉及到的row加上行锁即可以保证另一个事务无法修改这一行。但是这解不了幻读的问题,因为别的事务可能insert的是别的行。这时候,需要引入gap lock。不仅锁这一个row,还锁这个row的前后间隙。具体怎么锁,根据查询条件是走唯一索引还是非唯一索引,是走等值匹配还是范围匹配有不同的gap lock lock的范围,但一个原则就是:保证你这个语句的查询范围内的数据不会被其他事务insert进去。
  • 事务的两段锁:
    • 在事务的执行过程中,随时可以进行锁定,但只有事务执行完毕commit或者rollBack的时候,才会释放锁。

MVCC 多版本并发控制

  • 前面说锁分为读锁和写锁,这是一种悲观锁,MVCC是一种乐观锁,通过版本号控制,读副本的方式,来使得select读不用加锁,每次都读副本,同时保证读到的都是事务开始之前写入的数据。因为大多数数据库操作都是读多写少的,通过MVCC,读操作不用加锁,减少了锁冲突的概率,提高吞吐。select和事务又有啥关系呢?对于mysql,默认是auto-commit模式,如果不显示的开启一个事务,每个查询都被当作一个事务来执行。
  • mvcc怎么实现的
    • 每条记录后面增加两个version,创建version和删除version。
    • 对于select语句,只筛选那些创建version小于等于事务version(保证查询到的记录在当前事务开始之前就已经存在了),且删除version在当前version之后的(保证记录在当前事务开始的时候,未被删除)
    • insert 语句:插入新一行,创建version等于当前事务version
    • update语句:新插入一行,创建version等于当前事务version,之前行的删除version设置为当前事务version
    • delete语句: 当前行的删除version设置为当前事务version。

快照读和当前读

  • select语句读的是快照,通过读快照,在RR级别也不会有幻读,对于select for update这种当前读,通过next-key lock解决幻读问题。

refer

06-28 10:18