不同存储引擎支持的锁
存储引擎 表级锁 行级锁 页级锁MyISAM 支持 不支持 不支持
InnoDB 支持 支持 不支持
MEMORY 支持 不支持 不支持
BDB 支持 不支持 支持
演示InnoDB锁
数据准备
-- 创建db13数据库 CREATE DATABASE db13; -- 使用db13数据库 USE db13; -- 创建student表 CREATE TABLE student( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), age INT, score INT ); -- 添加数据 INSERT INTO student VALUES (NULL,'张三',23,99),(NULL,'李四',24,95), (NULL,'王五',25,98),(NULL,'赵六',26,97);共享锁
-- 标准语法 SELECT语句 LOCK IN SHARE MODE; -- 窗口1 /* 共享锁:数据可以被多个事务查询,但是不能修改 */ -- 开启事务 START TRANSACTION; -- 查询id为1的数据记录。加入共享锁 SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; -- 查询分数为99分的数据记录。加入共享锁 SELECT * FROM student WHERE score=99 LOCK IN SHARE MODE; -- 提交事务 COMMIT; -- 窗口2 -- 开启事务 START TRANSACTION; -- 查询id为1的数据记录(普通查询,可以查询) SELECT * FROM student WHERE id=1; -- 查询id为1的数据记录,并加入共享锁(可以查询。共享锁和共享锁兼容) SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; -- 修改id为1的姓名为张三三(不能修改,会出现锁的情况。只有窗口1提交事务后,才能修改成功) UPDATE student SET WHERE id = 1; -- 修改id为2的姓名为李四四(修改成功,InnoDB引擎默认是行锁) UPDATE student SET WHERE id = 2; -- 修改id为3的姓名为王五五(注意:InnoDB引擎如果不采用带索引的列。则会提升为表锁) UPDATE student SET WHERE id = 3; -- 提交事务 COMMIT;排他锁
-- 标准语法 SELECT语句 FOR UPDATE; -- 窗口1 /* 排他锁:加锁的数据,不能被其他事务加锁查询或修改 */ -- 开启事务 START TRANSACTION; -- 查询id为1的数据记录,并加入排他锁 SELECT * FROM student WHERE id=1 FOR UPDATE; -- 提交事务 COMMIT; -- 窗口2 -- 开启事务 START TRANSACTION; -- 查询id为1的数据记录(普通查询没问题) SELECT * FROM student WHERE id=1; -- 查询id为1的数据记录,并加入共享锁(不能查询。因为排他锁不能和其他锁共存) SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; -- 查询id为1的数据记录,并加入排他锁(不能查询。因为排他锁不能和其他锁共存) SELECT * FROM student WHERE id=1 FOR UPDATE; -- 修改id为1的姓名为张三(不能修改,会出现锁的情况。只有窗口1提交事务后,才能修改成功) UPDATE student SET WHERE id=1; -- 提交事务 COMMIT;注意:锁的兼容性
共享锁和共享锁 兼容
共享锁和排他锁 冲突
排他锁和排他锁 冲突
排他锁和共享锁 冲突
演示MyISAM锁数据准备
-- 创建product表 CREATE TABLE product( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), price INT )ENGINE = MYISAM; -- 指定存储引擎为MyISAM -- 添加数据 INSERT INTO product VALUES (NULL,'华为手机',4999),(NULL,'小米手机',2999), (NULL,'苹果',8999),(NULL,'中兴',1999);读锁
-- 标准语法 -- 加锁 LOCK TABLE 表名 READ; -- 解锁(将当前会话所有的表进行解锁) UNLOCK TABLES; -- 窗口1 /* 读锁:所有连接只能读取数据,不能修改 */ -- 为product表加入读锁 LOCK TABLE product READ; -- 查询product表(查询成功) SELECT * FROM product; -- 修改华为手机的价格为5999(修改失败) UPDATE product SET price=5999 WHERE id=1; -- 解锁 UNLOCK TABLES; -- 窗口2 -- 查询product表(查询成功) SELECT * FROM product; -- 修改华为手机的价格为5999(不能修改,窗口1解锁后才能修改成功) UPDATE product SET price=5999 WHERE id=1;写锁
-- 标准语法 -- 加锁 LOCK TABLE 表名 WRITE; -- 解锁(将当前会话所有的表进行解锁) UNLOCK TABLES; -- 窗口1 /* 写锁:其他连接不能查询和修改数据 */ -- 为product表添加写锁 LOCK TABLE product WRITE; -- 查询product表(查询成功) SELECT * FROM product; -- 修改小米手机的金额为3999(修改成功) UPDATE product SET price=3999 WHERE id=2; -- 解锁 UNLOCK TABLES; -- 窗口2 -- 查询product表(不能查询。只有窗口1解锁后才能查询成功) SELECT * FROM product; -- 修改小米手机的金额为2999(不能修改。只有窗口1解锁后才能修改成功) UPDATE product SET price=2999 WHERE id=2; 演示悲观锁和乐观锁
悲观锁的概念
就是很悲观,它对于数据被外界修改的操作持保守态度,认为数据随时会修改。
整个数据处理中需要将数据加锁。悲观锁一般都是依靠关系型数据库提供的锁机制。
我们之前所学的行锁,表锁不论是读写锁都是悲观锁。
乐观锁的概念
就是很乐观,每次自己操作数据的时候认为没有人会来修改它,所以不去加锁。
但是在更新的时候会去判断在此期间数据有没有被修改。
需要用户自己去实现,不会发生并发抢占资源,只有在提交操作的时候检查是否违反数据完整性。
悲观锁和乐观锁使用前提