ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

数据库事务的并发-锁机制-mysql

2022-07-04 19:03:40  阅读:126  来源: 互联网

标签:加锁 name 会话 -- 数据库 linelock 并发 mysql 操作


数据库为什么需要锁

锁机制:解决因资源共享而造成的并发问题。

事务在并发执行时,对同一张表(或同一条数据)进行操作而引发的问题

示例:买最后一件衣服X

A: X 买:X加锁->试衣服...下单..付款..打包->X解锁

B: X 买:发现X己被加锁,等待X解锁, X己出售

锁分类

操作类型

a. 读锁(共享锁):对同一个数据(衣服),多个读操作可以同时进行,互不干扰。

b. 写锁(互斥锁):如果当前写操作没有完毕(买衣服的一系列操作),则无法进行其他的读操作、写操作

操作范围

a. 表锁
一次性对一张表加锁
MyISAM存储引擎默认使用表锁
开销小,加锁快,无死锁,但锁的范围大,容易发生锁冲突,并发度低

b. 行锁
一次性对一条数据加锁
InnoDB存储引擎默认使用行锁
开销大,加锁慢,容易出现死锁,锁的范围较小,不容易发生锁冲突,并发度高
(很小概率发生高并发问题:脏读、幻读、不可重复读、丢失更新等问题)

c. 页锁

建议:高并发采用InnoDB,否则采用MyISAM

(1)表锁(MyISAM)

锁相关命令

增加锁:
locak table 表1 read/write,表2 read/write,…

査看加锁的表:
show open tables ;

释放锁:
unlock tables ;

会话 session :每一个访问数据的dos命令行、数据库客户端工具都是一个会话

准备数据

create table tablelock
(
id int primary key auto_increment, --自增操作MYSQL/SQLSERVER支持;oracle需要借助于序列来实现自增
name varchar(20)
)engine myisam;

insert into tablelock(name) values('al');
insert into tablelock(name) values('a2');
insert into tablelock(name) values('a3');
insert into tablelock(name) values ('a4');
insert into tablelock(name) values ('a5');
commit;

===加读锁

会话0:

lock table tablelock read ;  --对tablelock加读锁

-- 测试对tablelock的读与写
select * from tablelock; --读(査),可以
delete from tablelock where id =1 ; --写(增刪改),不可以

-- 测试对其他表的读与写
select * from emp ; --读,不可以
delete from tablelock where eno = 1; --写,不可以

小结:
如果某一个会话对A表加了read锁,则该会话可以对A表进行读操作、不能进行写操作;且该会话不能对其他表进行读、写操作。
--即如果给A表加了读锁,则当前会话只能对A表进行读操作。

image

会话1 (其他会话):

select * from tablelock; --读(査),可以
delete from tablelock where id =1 ; --写,需要"等待"会话0将锁释放

select * from emp ; --读(査),可以
delete from emp where eno = 1; -- 写,可以

--总结:
会话0给A表加了锁,则其他会话:
a.可以对其他表(A表以外的表)进行读、写操作
b.对A表:读-可以;写-需要等待释放锁。

===加写锁:

会话0:
lock table tablelock write ;

结论和读锁大致一样:
当前会话(会话0)可以对加了写锁的表进行任何操作(增刪改査);但是不能操作其他表

其他会话:
对会话0中加写锁的表可以进行增删改查的前提是:等待会话0释放写锁

进行了两次加锁,Navicat死了
刚试了貌似只有读锁可以反复加,写锁只能一个会话加,这也符合上一节课的逻辑

MySQL表级锁的锁模式

MyISAM在执行査询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(DML)前,会自动给涉表加写锁。所以对MyISAM表进行操作,会有以下情况:
a、 对MyISAM表的读操作(加读锁),不会阻塞其他进程(会话)对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。
b、对MyISAM表的写操作(加写锁).会阻塞其他进程(会话)对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。

分析表锁定

查看哪些表加了锁:
show open tables ; -- 1代表被加了锁

分析表锁定的严重程度:
show status like 'table%' ;
image

Table_locks_immediate: 即可能获取到的锁数
Table_locks_waited: 需要等待的表锁数(如果该值越大,说明存在越大的锁竞争)

建议:
Table_locks_immediate/Table_locks_waited > 5000,建议采用InnoDB引擎,否则MyISAM引擎

如果需要等待的表锁数大了,这个比例越低,表示锁冲突越严重,为什么要选择MyISAM,不应该是才用InnoDB

(2)行锁(InnoDB)

行锁相关命令

表锁是通过unlock tables,也可以通过事务解锁;行锁是通过事务解锁。

关闭自动commit

--mysql默认自动commit; oracle默认不会自动commit ;
为了研究行锁,暂时将自动commit关闭,以后需要通过commit

将自动提交关闭: 共有三种方式

-- 关闭自动commit;

 set autocommit =0 ;
 start transaction ;
 begin;

准备数据

create table linelock
(
id int(5) primary key auto_increment,
name varchar(20)
)engine=innodb ;

insert into linelock(name) values ('1');
insert into linelock(name) values ('2');
insert into linelock(name) values ('3');
insert into linelock(name) values ('4');
insert into linelock(name) values ('5');

commit ;

写锁

两个会话update或delete同一条数据(即便是第一个会话刚插入还没有来得及提交的数据)

操作同一条数据
会话0:写操作
insert into linelock values ('a6');

会话1:写操作同样的数据
update linelock set name='ax' where id = 6;

image

image

小结:
如果会话x对某条数据a进行DML操作(研究时:关闭了自动commit的情况下),则其他会话必须等待会话x结束事务(commit/rollback)后才能对数据a进行操作。

操作不同数据

会话0:写操作
insert into linelock values(8, 'a8');

会话1:写操作,不同的数据
update linelock set name='ax' where id = 5;

小结:
行锁,一次锁一行数据;因此如果操作的是不同数据,则不干扰。

行锁会转为表锁

如果没有索引,则行锁会转为表锁

show index from linelock ;
alter table linelock add index idx_linelock_name(name);

-- 索引未失效
会话0:写操作
update linelock set name = 'ai' where name = '3';
会话1: 写操作,不同的数据
update linelock set name = 'diX' where name = '4' ;

-- 索引失效
会话0:写操作
update linelock set name = 'ai' where name = 3 ;
会话1:写操作,不同的数据
update linelock set name = 'aiX' where name = 4;
-- 可以发现数据被阻塞了(加锁)

原因: 如果索引类 发生了类型转换,则索引失效。因此此次操作,会从行锁转为表锁。

间隙锁

行锁的一种特殊情况:间隙锁:值在范围内,但却不存在

update linelock set name = 'x' where id >1 and id<9 ; -- 此时linelock表中没有id=7的数据

在此where范围中,没有 id=7的数据,则id=7的数据成为间隙。Mysql会自动给间隙加锁->间隙锁。即本题会自动给id=7的数据加间隙锁(行锁)。

行锁:如果有where,则实际加锁的范围就是where后面的范围(不是实际的值)

读锁

如果仅仅是査询数据,能否加锁?

可以,通过for update对query语句进行加锁。
select * from linelock where id=2 for update;

image

MySQL行级锁的锁模式

InnoDB默认采用行锁;

缺点:比表锁性能损耗大。

优点:并发能力强,效率高。

因此建议,高并发用InnoDB,否则用MyISAM.

加锁机制规律总结

表锁:
会话(事务) 对那张表加锁,那当前会话 就只能操作那张表,如果是读锁,那就只能读,如果是写锁,那就可以增删改查。

其他会话 对该表操作: 如果是读锁,那就可以读,写的话需要等待锁释放;如果是写锁的话,读与写 都需要等待锁释放。

行锁:上面的表换成行

标签:加锁,name,会话,--,数据库,linelock,并发,mysql,操作
来源: https://www.cnblogs.com/jiyuchen1/p/16442664.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有