首页 > 数据库 >Mysql、(七) 锁机制

Mysql、(七) 锁机制

时间:2023-02-24 21:23:43浏览次数:53  
标签:事务 行锁 线程 MyISAM Mysql 机制 where id

@

目录


一、锁的概念

  • 锁是计算机协调多个进程或线程并发访问某一资源的机制。
  • 在数据库中,除了传统的计算资源(CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是数据库必须解决的一个问题。锁冲突也是影响数据库并发访问性能的一个重要因素。

锁的分类

  • 锁从对数据的操作类型可以分为 读锁和写锁,从对数据操作粒度可以分为 表锁和行锁。
  • 读锁:针对同一份数据,多个读操作可以同时进行而不会互相影响;
  • 写锁:当前写操作没有完成前,它会阻断其它写锁和读锁;

二、读锁案例(MyISAM引擎)

加锁: lock table tbl_name write/read:
解锁: unlock tables;
查看使用锁的情况:show open tables;

  • 线程1给 dept表添加了读锁
  • 线程1读取自己的表、读取其它表
    在这里插入图片描述
  • 线程1更新自己的表
    在这里插入图片描述
  • 线程2读取加锁的表、线程2更新加锁的表
    在这里插入图片描述

总结:
添加读锁的线程只能对本表进行读取,不能够修改本表也不能读取或修改其他表;
其它线程能够访问到加锁的表,但是修改操作会被阻塞,只有加锁的线程取消锁后本线程才能够进行写操作。

三、写锁案例(MyISAM引擎)

  • 添加写锁的线程能够对本表进行读操作和写操作,但是不能够对其它表进行读/写操作;
  • 其它线程对加锁的表的读和写操作会被阻塞,需要释放锁后才能读取;

四、MyISAM引擎锁总结

  1. MyISAM在执行查询语句(SELECT)前,会自动给所涉及到的所有表添加表锁,在执行增删改操作前,会自动给涉及到的表加写锁。
  2. MyISAM的表级锁有两种模式:
    在这里插入图片描述
  3. 对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读请求。只有当读锁释放后才会执行其它进程的写操作;
  4. 对MyISAM表的写操作(加写锁),会阻塞其它进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。
  5. MyISAM适合于读操作多的,它的写锁会阻塞其他线程的所有操作。

五、如何分析表锁定

SQL: show status like 'table%';
在这里插入图片描述
table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1;
table_locks_waited:出现表级锁定争用而发生等待的次数。(不能立即获取锁的次数,每等待一次锁值加1),此值较高说明存在严重的表级锁争用情况。

六、行锁理论

先回顾以下数据库事务的特性ACID:

  • 原子性(A):事务是一个原子操作单元,其对数据的修改,要么全部执行,要么全都不执行。
  • 一致性(C):在事务开始和结束的时候,数据都必须保证一致性状态。一致性强调事务的中间状态数据对外部不可见;比如A向B转账,不可能A扣了钱,B却没收到。
  • 隔离性(I):多个事务的时候,相互之间不能够干扰;比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
  • 持久性(D):事务完成后对于数据的修改是永久的,即使出现故障也能够保持。
    !!! 原子性和一致性的的侧重点不同:原子性关注状态,要么全部成功,要么全部失败,不存在部分成功的状态。而一致性关注数据的可见性,中间状态的数据对外部不可见,只有最初状态和最终状态的数据对外可见

再回顾下并发问题:

  • 脏读:事务A读取了事务B更新的数据,然后事务B回滚,那么A读到的就是脏数据;
  • 不可重复度:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
  • 幻读:事务A在读取数据时,事务B在该范围内插入了新的行,当A再去读取数据时会发现新增的行。

四种隔离级别:

  • 读未提交(read uncommitted):事务B可以读取事务A未提交的内容,会产生脏读;
  • 读已提交(read committed):一个事务只能够读取到已经提交的内容。这种隔离级别也支持不可重复读。
  • 可重复读(repeatable read):确保一个事务的多个实例在并发读取数据时,会看到相同的数据行。
  • 串行化(Serializable):serializable是在每个读的数据行上加锁,在这个级别,可能会导致大量的超时和锁竞争。

在这里插入图片描述
查看数据库的隔离级别: show variables like 'tx_isolation';

1. 行锁演示

在这里插入图片描述
事务1 进行了某一行的更新,但是没有提交;
事务2 此时相对同一行进行更新,发现被阻塞;
事务1提交后,事务2解除阻塞正常更新;

2. 行锁失效变为表锁

当使用索引时不小心造成索引失效,此时会将数据库的行锁变为表锁。

3. 间隙锁的危害

在这里插入图片描述

  • 间隙锁的概念:
    当我们使用范围条件而不是相等条件检索数据时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做间隙(GAP);
  • 危害:
    因为Query执行过程中通过范围查找的话,它会锁定整个范围内所有的索引键值,即使这个键值不存在。间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜锁定,而造成阻塞无法插入数据。

4. 如何上锁

锁定一行有两种方式,分别是添加共享锁(lock in share mode) 和排他锁(for update);

1.添加共享锁

  • 命令:select * from dept where id=1 lock in share mode;
  • 案例:
# session1
start transaction;
select * from test where id = 1 lock in share mode;
# session2
start transaction;
select * from test where id = 1 lock in share mode;

此时 session1 和 session2都可以正常获取结果;

(1) 加入排他锁获取数据

# session3
start transaction;
select * from test where id = 1 for update;
Lock wait timeout exceeded; try restarting transaction

结果 session3 无法获取数据,直到超时或其它事务commit 后才能有结果;

(2) 共享锁之间更新

# session1
update test set name = 'kkkk' where id = 1; 

session1 能够获取结果;

# session2
update test set name = 'zzz' where id = 1;

session1 未 commit前提下 session2也执行对同一行的数据的修改操作。

Deadlock found when trying to get lock; try restarting transaction
或者
Lock wait timeout exceeded; try restarting transaction

此时会出现死锁或者锁超时现象。必须等到 session1完成事务之后 session2 才能够执行更新操作。

  • 共享锁总结:
    • 允许其它事务添加共享锁;
    • 不允许其它事务添加排他锁;
    • 当事务同时增加共享锁时,事务的更新必须等待先执行update操作的事务commit之后才能执行,否则很容易造成死锁。

2. 添加排他锁

  • 命令:select * from dept where id=2 for update;
  • 案例:

(1) 排他锁之间读取数据

# session1 
start transaction;
select * from test where id = 1 for update;
# session2
start transaction;
select * from test where id = 1 for update;

当session1 执行查询后(未提交),session2的查询会被阻塞;直到session1 提交后session2才能获取数据;
查询都不被允许,更不用说更新操作了。

(2) 加入共享锁后尝试读取数据

# session3
select * from test where id = 1 lock in share mode;

结果一样也是阻塞。

  • 排他锁总结:
    • 事务之间不允许其它排他锁或共享锁读取数据,更新数据更不可能;
    • 一次只能一个排他锁执行 commit之后,其他事务才能够执行;

5. 行锁总结

在这里插入图片描述
在这里插入图片描述

  • 分析行锁定
    show status like 'innodb_row_lock%';
    在这里插入图片描述

参考文章:

MySQL 共享锁 (lock in share mode),排他锁 (for update)

标签:事务,行锁,线程,MyISAM,Mysql,机制,where,id
From: https://www.cnblogs.com/istitches/p/17153170.html

相关文章

  • Mysql、(三) 体系结构与存储引擎
    @目录一、Mysql体系结构概览二、存储引擎概述三、各种存储引擎特性1.Innodb存储引擎的存储方式2.MyISAM存储引擎的特性3.存储引擎的选择一、Mysql体系结构概览整个M......
  • Mysql、(四) 索引优化
    @目录一、查看SQL执行频率二、定位低效率执行SQL1.showprocesslist:2.慢查询日志三、SQL中JOIN四、explain性能分析五、索引优化1)单表索引优化2)两表索引优化3)......
  • Mysql、(五) 千万级数据批量插入
    @目录一、开启函数创建错误日志二、创建sql脚本1)创建函数2)创建存储过程3)调用存储过程一、开启函数创建错误日志查看是否开启:showvariableslike'%log_bin......
  • Mysql、(二) 索引
    @目录一、索引概述二、索引的优势劣势三、索引结构BTREE索引B+TREE索引1.结构介绍2.Mysql中的B+树四、索引分类4.1InnoDB_聚簇索引聚簇索引的优点:聚簇索引的缺点:4.2In......
  • MySQL备份---还原
    1.全量备份(数据+结构)#mysqldump-uroot-p123456-A>备份文件路径2.指定库备份(数据+结构)#mysqldump-uroot-p123456库名>备份文件路径3.多个库备份(数据+结构)#mysqld......
  • mysql主从自动搭建
    1.主服务器​​master.sh​​#!/bin/bash#====================================================#Author:Mr.Song#CreateDate:2019-02-21#Description:autoconfig......
  • mysql半同步
    什么是半同步复制所谓的半同步复制就是master主服务器每commit一个事务(简单来说就是做一个改变数据的操作),要确保slave从服务器接收完主服务器发送的binlog日志文件并写入......
  • MySQL数据库架构&SQL注入漏洞
    1.查找zblog数据库中有哪些表查找目标表(zbp_member)中的的字段查找目标表中的目标数据(管理员的用户名密码)4.使用UNION语句替换掉原有查询结果,显示zblog数据库中的所有表。网......
  • Mysql记录
    远程操作mysql远程连接:mysql-hhost-uusername-p'password'mysql远程dump并导出:mysqldump-hhost-uusername-p'password'库名>dump.sqlmysql直接执行......
  • MySQL数据库学习笔记1
    MySQL数据库学习笔记1MySQL服务器启动与连接#启动mysql.serverstart#连接mysql-uroot-pMySQL数据库的数据模型客户端访问MySQL数据库,是与数据库管理系统交......