深入理解MySQL数据库各种锁(总结)

2020-08-12  本文已影响0人  时间煮菜

0. 对MySQL的锁了解吗

1. 隔离级别与锁的关系

2. MySQL三种锁的级别。按照锁的粒度分数据库锁有哪些?锁机制与InnoDB锁算法

在关系型数据库中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )

MyISAM和InnoDB存储引擎使用的锁:

表级锁

行级锁

页面锁

封锁粒度小:

3. MySQL常见的锁类型?

排它锁(Exclusive Lock)/ X锁

SELECT * FROM table_name WHERE ... FOR UPDATE;   # 排它锁

共享锁(Shared Lock)/ S锁

SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE;  # 共享锁

意向锁(Intention Locks)

意向锁都是表锁。意向锁的存在是为了允许事务在行级上的锁和表级上的锁同时存在。

由于InnoDB存储引擎支持的是行级别的锁,因此意向锁(因为意向锁是表锁)其实不会阻塞除全表扫以外的任何请求。故表级意向锁与行级锁的兼容性如下所示

是否兼容当前锁模式 X IX S IS
X 冲突 冲突 冲突 冲突
IX 冲突 兼容 冲突 兼容
S 冲突 冲突 兼容 兼容
IS 冲突 兼容 兼容 兼容

意向锁到底有什么作用

4. 知道mysql中的锁吗,说一下表锁,行锁,如何上锁(for update),举个例子在什么时候事务会进入阻塞状态

5. mysql共享锁与排他锁

参考

共享锁与排他锁是行级锁

image

6. 行锁的三种算法,以及解决的问题

参考

InnoDB行锁时通过给索引上的索引项加锁来实现的,Oracle时通过在数据块中相对应数据行加锁来实现。

InnoDB这种行锁实现特点意味着,只有通过索引条件检索条件数据,InnoDB才使用行锁,否则InnoDB将使用表锁。

行锁的三种算法:

image

记录锁 Record Locks

间隙锁 Gap Locks

SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;

这条语句阻止其他事务插入10和20之间的数字,无论这个数字是否存在。 间隙可以跨越0个,单个或多个索引值。

Next-key锁

7. 实现一个读写锁

https://blog.csdn.net/u014316026/article/details/78726459

共享锁:

image

排他锁:

image

8. 什么是三级封锁协议?

一级封锁协议

二级封锁协议

三级封锁协议

9. 什么是两段锁协议?

https://www.cnblogs.com/mysql-hang/articles/11027685.html

image

10. 什么是乐观锁和悲观锁?

乐观锁

乐观锁不是数据库自带的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了。

乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改(天真),操作数据时不会上锁,但是更新时会判断在此期间有没有别的事务更新这个数据,若被更新过,则失败重试;适用于读多写少的场景。

乐观锁的实现方式有:

  1. 版本号机制:加一个版本号或者时间戳字段,每次数据更新时同时更新这个字段;

    • 一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

    • 场景:

      • 假设数据库中帐户信息表中有一个 version 字段,当前值为 1 ;而当前帐户余额字段( balance )为 $100 。

      • 操作员 A 此时将其读出( version=1 ),并从其帐户余额中扣除 50(100-$50 )。

      • 在操作员 A 操作的过程中,操作员B 也读入此用户信息( version=1 ),并从其帐户余额中扣除 20 (100-$20 )。

      • 操作员 A 完成了修改工作,将数据版本号加一( version=2 ),连同帐户扣除后余额( balance=$50 ),提交至数据库更新,此时由于提交数据版本大于数据库记录当前版本,数据被更新,数据库记录 version 更新为 2 。

      • 操作员 B 完成了操作,也将版本号加一( version=2 )试图向数据库提交数据( balance=$80 ),但此时比对数据库记录版本时发现,操作员 B 提交的数据版本号为 2 ,数据库记录当前版本也为 2 ,不满足 “ 提交版本必须大于记录当前版本才能执行更新 “ 的乐观锁策略,因此,操作员 B 的提交被驳回。

      • 这样,就避免了操作员 B 用基于 version=1 的旧数据修改的结果覆盖操作员A 的操作结果的可能。

    • 使用实例:

    1. SELECT data AS old_data, version AS old_version FROM …;
    2. 根据获取的数据进行业务操作,得到new_data和new_version
    3. UPDATE SET data = new_data, version = new_version WHERE version = old_version
    if (updated row > 0) {
    // 乐观锁获取成功,操作完成
    } else {
    // 乐观锁获取失败,回滚并重试
    }
  1. CAS算法:compare and swap(比较与交换),是一种有名的无锁算法。先读取想要更新的字段或者所有字段,更新的时候比较一下,只有字段没有变化才进行更新。一般情况下是一个自旋操作,即不断的重试

    • 无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。

    • CAS算法涉及到三个操作数

      • 需要读写的内存值(内存位置) V

      • 进行比较的值(原值) A

      • 拟写入的新值(新值) B

    • 当且仅当 内存位置V 的值等于 原值A 时,CAS通过原子方式用 新值B 来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试

    • CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。

乐观锁不是锁,乐观锁是一种思想,版本号机制和CAS算法是实现这种思想的一种实现方式

悲观锁

悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)

关闭自动提交后,我们需要手动开启事务。

// 1.开始事务
begin; 或者 start transaction;
// 2.查询出商品信息,然后通过for update锁定数据防止其他事务修改
select status from t_goods where id=1 for update;
// 3.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
// 4.修改商品status为2
update t_goods set status=2;
// 5.提交事务
commit; --执行完毕,提交事务

上述就实现了悲观锁,悲观锁就是悲观主义者,它会认为我们在事务A中操作数据1的时候,一定会有事务B来修改数据1,所以,在第2步我们将数据查询出来后直接加上排它锁(X)锁,防止别的事务来修改事务1,直到我们commit后,才释放了排它锁。

11. 什么是死锁?

12. 死锁怎么解决?

13. 锁的优化策略

  1. 读写分离
  2. 分段加锁
  3. 减少锁持有的时间
  4. 多个线程尽量以相同的顺序去获取资源
上一篇 下一篇

猜你喜欢

热点阅读