数据库学习--MySQL锁

锁是计算机协调多个进程或线程并发访问某一资源的机制

特点

显著特点是不同的存储引擎支持不同的锁机制

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低

  • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率最小,并发度最高

表级锁:

两种模式:表 共享锁【读锁】(级别) > 表 独占锁【排他锁/写锁】​

表级锁的存储引擎:

MyISAM:引擎

MEMORY:引擎

不能访问别的表

特点

  • 作用范围:表级别
  • 如果加了读锁,对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的 请求
  • 如果加了读锁,可以查询锁定表中的记录,但是更新或者访问其他表都会提示错误【对自己】
  • 如果加了写锁,对MyISAM表的写操作,会阻塞其他用户对同一表的读 和 写 请求
  • 如果加了写锁,可以读取表中的记录,但是更新或者访问其他表都会提示错误,可以写表中的数据【加锁表】【对自己】

如何加锁

MyISAM在执行查询语句(select)前,会自动给涉及的所有表加读锁,在执行更新操作

在执行(update、delete、insert)前,会自动给表加写锁

加锁

lock table 表名 read [local],
Lock table 表名 write [local]

多表加锁:
lock table 表名1,表名2 read/write [local]

解锁

unlock tables;

查看锁的情况

show status like 'table%'

	table_locks_immediate:加锁次数
	table_locks_waited : 等待次数

show status like '%lock%'   # 看到的更全面

show processlist #此命令可以查看那些sql在等待锁 
show open tables #当前被锁住的表以及锁的次数

并发插入:由读锁带来的问题解决办法

加锁带来的问题

myisam有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别对应为0,1,2

concurrent_insert=0,不允许并发插入【NEVER】
concurrent_insert=1,如果myisam没有空洞(即表的中间没有被删除的行),myisam允许在一个进程读表的同时,另一个进程从表尾插入记录,【默认设置】【AUTO】
concurrent_insert=2,无论有没有空洞,都在表尾插入【ALWAYS】

会产生碎片,用optimize table 表名;解决(优化)

读写锁优先级

默认情况下,写 > 读

设置写锁的最多次数

设置:
	max_write_lock_count=次数
锁次数=次数值时,执行读操作
有了这样的设置,当系统处理一个写操作后,就会暂停写操作,给读操作执行的机会。

降低写操作的优先级,给读操作更高的优先级

low_priority_updates=1  降低写的优先级
sql_low_priority_updates=1 
默认值为0
写语句变更为:
update/insert/delete/...  low_priority
再用

设置写内存

max_allowed_packet=1M  #限制接受的数据包的大小,大的插入和更新会被限制掉,导致失败

net_buffer_length=2K-16M  #设置insert语句缓存值,多数据同时插入(),(),()。。。

bulk_insert_buffer_size=8M  # 一次性insert语句插入的大小

优化办法

  • concurrent_insert=2
  • optimize table 表名整理碎片
  • 设置优先级
  • 设置写内存/写的数量次数

使用场景

第一种情况是:事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。

第二种情况是:事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。

行级锁/事务锁

行级锁模式

读锁/共享锁(S):允许一个事务去读一行,组织其他事务获得相同数据集的排他锁;

​ 允许其他线程上读锁,但是不允许上写锁。

写锁/排他锁(X):允许获得排他锁的事务更新数据,组织其他事务取得相同数据集的共享读锁和排他锁

​ 不允许其他线程上任何锁。

意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加锁前必须先取得该表的IS锁;为防止形成死锁

意向排他锁(IX):事务打算给数据加行排他锁,事务在给一个数据行加排他锁前必须取得该表的IX锁;为防止形成死锁【不主张用】

兼容 X IX S IS
X × × × ×
IX × 兼容 × 兼容
S × × 兼容 兼容
IS × 兼容 兼容 兼容

如果一个事务请求的锁模式与当前锁兼容,InnoDB就将请求的锁授予该事务;

反之。不兼容,该事务就要等待锁释放

行级锁的存储引擎:InnoDB

特点

  • InnoDB行锁时通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将行锁升级为表锁 【操作的行必须有索引】
  • 意向锁是InnoDB自动加的,不需要用户干预。
  • 对于update、delete、insert,自动给涉及数据集加排他锁;对于普通的select【没有 显示加锁的情况】,不加任何锁
  • 研究行锁时,需要将自动提交关闭,默认开启:set autocommit=0;
  • 多个客户端都要设置 set autocommit=0;

select语句加行锁

意向共享锁/读锁:select ***** lock in share mode
意向排他锁/写锁:select ***** for update

释放锁

commit
rollback

innodb注意事项

当我们给某一条数据上了排他锁:
	其他人操作不了这条数据;想操作。排队,等其他人释放(commit;)

	其他人对这条数据没有任何权限,但是并不影响其他客户修改其他数据

	能查询,但是查不到最新的【隔离】

	即使字段加了索引,但是你在使用偷换了数据类型,那么索引失效,最终加上表锁【0   》   ‘0 ’】

间隙锁

操作的数据的自增值中间有间隙的时候,将间隙(缺的部分)自动锁起来

也能锁住不存在的条件(一般为子增值)

锁住范围内的所有数据 =》 指定条件的时候给一个确定的范围

造成阻塞

查询行级锁征用情况

show status like 'innobd_row_lock%'
innobd_row_lock_waits   innobd_row_lock_time_

优化行级锁

  • 尽量用较低的隔离级别,精心设置索引,并尽量使用索引当问数据,使加锁更精确,从而减少锁冲突的机会
  • 选择合理的事务大小,小事务发生锁冲突的几率也更小
  • 给记录集显示【手动】加锁时,最好一次性请求足够级别的锁,比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时在申请排他锁,这样容易产生死锁
  • 尽量用相等条件访问数据,可以避免间隙锁对并发插入的影响
  • 对于特定的事务,可以使用表锁来提高处理速度或减少死锁的可能

猜你喜欢

转载自blog.csdn.net/qq_43320162/article/details/85322452