计算机毕设网站开发中期报告,干净简约高端的网站,自己做网站怎么租服务器,广州各区进一步强化MySQL 中锁的概念
排它锁#xff08;Exclusive Lock#xff09;
X 锁#xff0c;也称为写锁#xff0c;若事务T对对象A加上X锁#xff0c;则只允许T读取和修改A#xff0c;其他任何事物都不能再对A 加任何锁#xff0c;直到T释放A上的锁。 SELECT…FOR UPDATE 对读取的…MySQL 中锁的概念
排它锁Exclusive Lock
X 锁也称为写锁若事务T对对象A加上X锁则只允许T读取和修改A其他任何事物都不能再对A 加任何锁直到T释放A上的锁。 SELECT…FOR UPDATE 对读取的行记录加一个X锁其他事务不能对已锁定的行加上任何锁。
共享锁Shared Lock
**S 锁**也称为读锁若事务T对数据对象A加上S锁则事务T可以读A但不能修改A其他事务只能再对A加S锁而不能加X锁直到T释放A上的S锁。 SELECT…LOCK IN SHARE MODE对读取的行记录加一个S锁其他事务可以向被锁定 的行加S锁但是如果加X锁则会被阻塞。
活锁
事务T1封锁了RT2又请求封锁R于是T2等待T3也请求封锁R当T1释放了R 上的锁系统首先批准了T3的请求T2继续等待这就是活锁。
死锁
事务T1封锁了R1T2封锁了R2T1又请求封锁R2因为T2已经封锁了R2于是T1等待T2释放R2上的锁接着T2又申请封锁R1因为T1已经封锁了R1T2只能等待T1释放R1上的锁这就是死锁。 解决死锁的方法 一次封锁法 每个事务必须将所有要使用的数据全部加锁否则就不能执行弊端 加大封锁范围降低了并发速度。
乐观锁
总是假设最好的情况在事务提交前不会对数据进行锁定而是在更新数据时会进行版本或时间戳的比较以确定数据是否被其他事务修改过。如果数据没有被修改则允许提交如果数据被修改则需要进行冲突解决
悲观锁
总是假设最坏的情况在整个事务过程中假设其他事务会对数据进行修改因此在读取或修改数据时会先对数据进行锁定以防止其他事务对数据进行干扰排它锁、共享锁都是悲观锁共享资源每次只给一个线程使用其它线程阻塞用完后再把资源转让给其它线程
MySQL 行锁加锁的分析
版本使用 MySQL 8.2.0 MySQL InnoDB 中支持三种行锁的方式行锁Record Lock、间隙锁Gap Lock、临键锁Next-Key Lock默认加的是临键锁但是会根据不同的查询条件进行优化。创建一个 user 表用来测试表中 id 是主键索引name 是唯一索引salary 是普通索引gender 没有索引。
idnamesalarygender10惠月48000女20光济50000男30杰霖55000男40紫妤60000女50娜溱70000女
创建表并插入数据
CREATE TABLE user (id int(11) NOT NULL,name varchar(255) DEFAULT NULL,salary int DEFAULT NULL,gender varchar(255) DEFAULT NULL,PRIMARY KEY (id) USING BTREE,INDEX salary(salary) USING BTREE,UNIQUE INDEX name(name ASC) USING BTREE
);INSERT INTO user VALUES (10, 惠月, 48000, 女);
INSERT INTO user VALUES (20, 光济, 50000, 男);
INSERT INTO user VALUES (30, 杰霖, 55000, 男);
INSERT INTO user VALUES (40, 紫妤, 62000, 女);
INSERT INTO user VALUES (50, 娜溱, 75000, 女);加锁情况
-- 普通的select查询是快照读不加锁
SELECT * FROM user WHERE id30;
-- 查询时给主键索引加S共享锁时是当前读
SELECT * FROM user WHERE id30 LOCK IN SHARE MODE;
-- 查询时加 X排他锁为当前读
SELECT * FROM user WHERE id30 FOR UPDATE
执行 SELECT * FROM … FOR UPDATE 会对表加上 IX 写意向锁表示有可能会对这些记录进行写操作并且给记录加一个X,REC_NOT_GAP锁定了该条数据。 执行SELECT * FROM … FOR SHARE 会对表加上一个 IS 读意向锁并且会给记录加一个S,REC_NOT_GAP。
主键索引
主索引等值查询数据存在的情况
事务 1
BEGIN;
SELECT * FROM user WHERE id30 FOR UPDATE;
-- SELECT * FROM user WHERE id40 FOR SHARE;
-- ROLLBACK查看锁的情况
-- mysql 8
SELECT * FROM performance_schema.data_locks;-- mysql 5.7
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;1、表锁是意向写锁 2、数据加行锁 各字段意思 INDEX_NAME 锁定索引的名称 PRIMARY 说明是主键索引 LOCK_TYPE 锁的类型RECORD 行锁 、 TABLE 表锁 LOCK_MODE 锁的模式IS 读意向锁、IX 写意向锁、S 读锁又称共享锁、X 写锁又称排它锁、GAP 间隙锁。 **LOCK_DATA **要锁定的数据当 LOCK_TYPE 是 RECORD行锁时。当锁在主键索引上时显示主键索的值。当锁是在辅助索引上时显示主索引和辅助索引的值。
LOCK_MODELOCK_DATA锁范围X,REC_NOT_GAP40id40 行锁X,GAP40id40 间隙锁不包含 40前开后开X40id40 临键锁包含 40前开后闭
事务 2 1、会对主索引 id30 添加行锁
BEGIN;
-- 更新会失败因为事务 1 对 id30 加行锁。
UPDATE user SET salary 56000 WHERE id 30;主索引等值查询数据不存在的情况
事务 1
BEGIN;
SELECT * FROM user WHERE id31 FOR UPDATE; -- 数据库中没有id30的记录查看加锁情况 1、表加的是意向写锁 2、id 加的是 GAP Lock范围是(30, 40) 注意 LOCK_MODE 是 X,GAP 表示间隙锁LOCK_DATA 是 40 表示锁定的范围是在 id 为 40 之前的间隙 事务 2 1、会锁住主索引 id31 所在的间隙
BEGIN;
-- 可以执行成功
UPDATE bostore.user SET salary 56000.00 WHERE id 30;
UPDATE bostore.user SET salary 63000.00 WHERE id 40;
-- 执行失败
INSERT INTO bostore.user VALUES (33, 六零, 68000.00, 女);主索引范围查询前闭后开情况
事务 1
BEGIN;
SELECT * FROM user WHERE id30 AND id33 FOR UPDATE;查看锁情况 1、 表示 IX 意向写锁 2、id30 是行锁 3、id40 加的是 GAP Lock范围是(30, 40) 事务 2
BEGIN;
-- 会阻塞
UPDATE user SET salary 57000.00 WHERE id 30;
INSERT INTO user VALUES (35, 六零, 68000.00, 女);
INSERT INTO user VALUES (33, 合吧, 64000.00, 女);
-- 不会阻塞
UPDATE user SET salary 63000.00 WHERE id 40;主索引范围查询前开后闭情况
事务 1
BEGIN;
SELECT * FROM user WHERE id30 AND id40 FOR UPDATE;查看锁情况 1、表加的是意向写锁 2、id40 加 NEXT-Key Lock范围是(30, 40] 事务 2
BEGIN;
-- 会阻塞
UPDATE user SET salary 63000 WHERE id 40;
INSERT INTO user VALUES (35, 六零, 68000, 女);
INSERT INTO user VALUES (33, 合吧, 64000, 女);-- 不会阻塞
UPDATE user SET salary 57000 WHERE id 30;
UPDATE user SET salary 78000 WHERE id 50;
INSERT INTO user VALUES (53, 考拉, 84000, 女);普通索引
普通索引普通索引只针对表中的单一列进行索引普通索引可以是唯一的也可以不唯一普通索引对于等值查询例如WHERE column value和范围查询例如WHERE column value都能提供较好的性能提升
普通索引等值查询数据存在的情况
事务 1
BEGIN;
SELECT * FROM user WHERE salary 62000 FOR UPDATE;查看锁情况 1、 表加意向写锁 IX 2、 索引salary加临键锁范围是(55000, 62000] 3、 主键 id 40 加行锁 4、 索引salary加间隙锁范围是(62000, 75000) 事务 2 1、 主键 id40 加了行锁不能更新和删除
-- 修改id40有行锁会阻塞
UPDATE user SET salary 63000 WHERE id 40;
UPDATE user SET name紫是 where salary 62000;2、salary 在(55000, 62000] 范围加了 NEXT-Key Lock针对该范围的 id 也会加锁insert 时salary 在此范围会阻塞 3、salary 在(62000, 75000)范围加了 GAP Lock避免幻读insert 时salary 在此范围会阻塞 4、 插入 salary55000时id30可以不阻塞id30会阻塞
-- id40 salary62000 之前有临键锁(55000, 62000]
-- 是对salary的锁但是整个区间都会被锁住包括主索引id
INSERT INTO user VALUES (35, 六零, 55000, 女); -- 阻塞
INSERT INTO user VALUES (51, 哈西, 55000, 女); -- 阻塞
-- id30 salary55000 之前没有间隙锁
INSERT INTO user VALUES (29, 湖西, 55000, 女); -- 不阻塞
5、 插入 salary62000时会阻塞
INSERT INTO user VALUES (39, 哈子, 62000, 女);
INSERT INTO user VALUES (44, 靠是, 62000, 女);
INSERT INTO user VALUES (55, 西欧, 62000, 女);
-- 自增id时也是会阻塞
INSERT INTO bostore.user(name, salary, gender) VALUES (学律, 62000, 女);6、插入 salary75000时id50 会阻塞id50 不阻塞
-- LOCK_MODE为X,GAP
-- LOCAK_DATA为75000, 50 表示 要插入salary为75000id50时会加锁即会阻塞
INSERT INTO user VALUES (29, 合吧, 75000, 女);
-- id 50 不会阻塞
INSERT INTO user VALUES (51, 欧下, 75000, 女);7、当salary 不在(55000, 62000] 和(62000, 75000)范围时id 不会加锁
INSERT INTO user VALUES (31, 湖西, 54000, 女);
INSERT INTO user VALUES (49, 离下, 54000, 女);
INSERT INTO user VALUES (45, 的大, 76000, 女);
UPDATE user SET salary 78000 WHERE id 50;-- id 30 和 salary 55000 不阻塞
INSERT INTO user VALUES (29, 六零, 50000, 女);
-- id 50 和 salary 75000 不阻塞
INSERT INTO user VALUES (63, 合吧, 94000, 女);普通索引等值查询数据不存在的情况
事务 1
BEGIN;
SELECT * FROM user WHERE salary 60000 FOR UPDATE;查看锁情况 1、表加意向写锁 2、salary 加间隙锁范围是(55000 62000) 事务 2 1、salary 在(55000 62000)范围加了 GAP Lockinsert 时salary 在此范围会阻塞 2、插入 salary55000时id30可以不阻塞id30会阻塞
INSERT INTO user VALUES (35, 六零, 55000, 女); -- 阻塞
INSERT INTO user VALUES (51, 哈西, 55000, 女); -- 阻塞
-- id30 salary55000 之前没有间隙锁
INSERT INTO user VALUES (29, 湖西, 55000, 女); -- 不阻塞3、插入 salary62000时id40 会阻塞id40 不阻塞
-- id 40 会阻塞
INSERT INTO user VALUES (39, 合吧, 62000, 女);
-- id 40 不会阻塞
INSERT INTO user VALUES (41, 欧下, 62000, 女);4、当 salary 不在(55000 62000)id 不会加锁
INSERT INTO user VALUES (31, 湖西, 54000, 女);
INSERT INTO user VALUES (39, 离下, 63000, 女);
UPDATE user SET salary 63000 WHERE id 40;-- id 30 和 salary 55000 不阻塞
INSERT INTO user VALUES (29, 六零, 50000, 女);
-- id 40 和 salary 62000 不阻塞
INSERT INTO user VALUES (41, 合吧, 65000, 女);普通索引范围查询前闭后开的情况
事务 1
BEGIN;
SELECT * FROM user WHERE salary55000 AND salary62000 FOR UPDATE;查看锁情况 1、表加意向写锁 2、salary 加 NEXT-Key Lock 范围是(50000, 55000] 3、salary 加 NEXT-Key Lock 范围是(55000, 62000] 4、id30 加行锁 事务 2 1、 插入 salary50000时id20可以不阻塞id20会阻塞
INSERT INTO user VALUES (19, 六零, 50000, 女); -- 不阻塞
INSERT INTO user VALUES (21, 哈西, 50000, 女); -- 阻塞
INSERT INTO user VALUES (41, 湖西, 50000, 女); -- 阻塞
2、 插入 salary55000时会阻塞
INSERT INTO user VALUES (29, 哈子, 55000, 女);
INSERT INTO user VALUES (35, 靠是, 55000, 女);
INSERT INTO user VALUES (44, 西欧, 55000, 女);
-- 自增id时也是会阻塞
INSERT INTO bostore.user(name, salary, gender) VALUES (学律, 55000, 女);3、 插入 salary62000时id40 会阻塞id40 不阻塞
-- 阻塞
INSERT INTO user VALUES (39, 合吧, 62000, 女);
-- 不阻塞
INSERT INTO user VALUES (41, 欧下, 62000, 女);4、当salary 不在(50000, 55000] 和(55000, 62000]范围时id 不会加锁
INSERT INTO user VALUES (31, 湖西, 44000, 女);
INSERT INTO user VALUES (49, 离下, 44000, 女);
INSERT INTO user VALUES (45, 的大, 66000, 女);-- id 20 和 salary 50000 不阻塞
INSERT INTO user VALUES (19, 六零, 40000, 女);
-- id 40 和 salary 62000 不阻塞
INSERT INTO user VALUES (53, 合吧, 94000, 女);5、id30 加行锁不能删除和更新
UPDATE user SET salary 56000 WHERE id 30;
UPDATE user SET name紫下 where salary 55000;普通索引范围查询前开后闭的情况
事务 1
BEGIN;
SELECT * FROM user WHERE salary55000 AND salary62000 FOR UPDATE;查看锁情况 1、表加意向写锁 2、salary 加 NEXT-Key Lock 范围是(55000, 62000] 3、salary 加 NEXT-Key Lock 范围是(62000, 75000] 4、id40 加行锁 事务 2 的加锁情况和上面类似
没有索引的情况
BEGIN;
SELECT * FROM user WHERE gender男 FOR UPDATE;查看加锁情况 InnoDB 的锁是加上在索引上的没有索引的时候就会给所有的记录都加上锁 NEXT-Key Lock相当于表锁。