锁的分级

  1. 全局锁

    1. flush tables with read lock
  2. 表级锁

    1. 表锁
      1. 对当前线程和其他线程都起作用
      2. lock tables … read/write — 加锁
      3. unlock tables — 解锁
    2. MDL(meta data lock)

数据库自动调用。增删改查是MDL读锁,修改表结果会加MDL写锁

  1. 行锁

表级锁

  • 表锁就是锁住整张表。
  • MDL工作在server层,目的是为了区分DDL(表结构改变语句,alert table)和DML(数据操作语句,数据的增删改),避免一个连接在查的时候,另一个线程改了表结构,导致拿到的数据结构和预期不符。MDL的读锁不互斥,读写、写写互斥。
    • DDL:表结构更改语句会获取MDL写锁
    • DML:数据增删改只会获取MDL的读锁

image.png
上图中,sessionA和B共享MDL读锁,所以A和B可以运行。但是C和D需要先获取MDL写锁,所以在A和B结束之前会被一直阻塞。

行锁

  1. 对数据修改会加行锁,当前读会加行锁,行锁在事务结束之后才会释放
  2. 每个事务都会有事务ID。
  3. 每条记录在更新的时候会打上当前事务id作为版本号:trx_id
  4. MVCC多版本并发控制和一致性视图有关,一致性视图其实就是一个活跃事务的数组。
  5. 在可重复读隔离级别下,一致性视图在事务启动时就创建,读已提交情况下,事务在第一条select语句下创建。

    事务的可见性

    image.png

  6. trx_id 小于低水位,也就是当前不活跃的事务,是可见数据。

  7. trx_id 大于高水位的,是在创建一致性视图后开启的事务,肯定不可见。
  8. trx_id 在高低水位之间的:
    1. 如果存在,说明是活跃事务,肯定不可见。
    2. 如果不存在,说明在当前事务之后创建,但是比当前事务更早提交。此处是不可见的(可重复度情况下)。

数据库的乐观锁实现

通过给字段加version字段,在update时添加version的约束,由于update是当前读,如果有其他事务在占用,会被阻塞,其他事务改完之后,version字段就会被改变,所以当前事务就会失效。需要开启新的事务。