首页 > 数据库 >MySQL锁的概念

MySQL锁的概念

时间:2025-01-03 20:32:37浏览次数:3  
标签:事务 记录 行锁 查询 概念 MySQL 操作 共享

  1. 锁的基本概念

    • 锁在 MySQL 中是一种并发控制机制,它确保在多用户或多事务环境下数据的完整性和一致性。当多个事务同时访问和操作数据库中的数据时,为了防止数据出现不一致、丢失更新、脏读、不可重复读和幻读等问题,就需要使用锁来协调这些事务的访问顺序。例如,在一个银行转账系统中,如果没有锁机制,两个事务同时对同一个账户进行操作,就可能导致数据错误。
  2. 锁的类型

    • 共享锁(S Lock,也叫读锁)
      • 共享锁允许同时有多个事务对同一数据进行读取操作。一个事务对数据加上共享锁后,其他事务可以继续对该数据加共享锁来读取,但不能加排他锁进行写操作。这是因为共享锁的目的是实现多个事务对数据的并发读取。例如,在一个图书馆的图书信息管理系统中,多个用户可以同时查询某一本书的信息,此时对图书信息表中的记录加共享锁,就可以满足这种并发读取的需求。
      • 共享锁的语法在不同的存储引擎和操作方式下有所不同。在 InnoDB 存储引擎中,使用SELECT... LOCK IN SHARE MODE语句来对查询的数据加共享锁。例如:SELECT * FROM books WHERE book_id = 1 LOCK IN SHARE MODE;,这表示在查询图书编号为 1 的图书信息时,对该记录加共享锁,其他事务可以同时对这条记录加共享锁进行读取,但不能进行写操作。
    • 排他锁(X Lock,也叫写锁)
      • 排他锁用于对数据进行写操作,如插入、更新和删除操作。当一个事务对数据加上排他锁后,其他事务不能对该数据加任何类型的锁,无论是共享锁还是排他锁,直到该事务释放排他锁。这是因为写操作通常需要对数据进行独占式的访问,以确保数据的准确性。例如,在一个库存管理系统中,当一个事务正在更新某一商品的库存数量时,对该商品的库存记录加排他锁,其他事务就不能同时对这条记录进行读取或写入操作,直到库存更新事务完成。
      • 在 InnoDB 存储引擎中,FOR UPDATE语句用于对查询的数据加排他锁。例如:SELECT * FROM inventory WHERE product_id = 1 FOR UPDATE;,这表示在查询商品编号为 1 的库存信息时,对该记录加排他锁,其他事务在这个锁释放之前不能对这条记录进行任何操作。
  3. 锁的粒度

    • 表锁
      • 表锁是对整个表进行锁定。它的实现相对简单,管理锁的开销较小,因为只需要维护一个表级别的锁状态。当一个事务对表加表锁后,其他事务对该表的任何操作(包括读取和写入)都需要等待锁的释放。这种方式在一些简单的场景下比较适用,例如对整个表进行批量更新或者备份操作时。
      • 在 MySQL 中,可以使用LOCK TABLES语句来手动加表锁。例如:LOCK TABLES orders WRITE;,这是对orders表加排他表锁(WRITE表示排他锁),用于对该表进行写操作。如果要加共享表锁,可以使用READ关键字,如LOCK TABLES customers READ;,这表示对customers表加共享表锁,用于对该表进行读操作。需要注意的是,在使用LOCK TABLES语句后,一定要记得使用UNLOCK TABLES语句来释放锁。
    • 行锁
      • 行锁是对表中的行进行锁定。它提供了更高的并发性能,因为不同的事务可以对同一表中的不同行进行加锁操作。这样可以允许多个事务同时对一张表进行读写操作,只要它们操作的是不同的行。不过,行锁的管理开销较大,因为需要为每一行维护锁状态。
      • InnoDB 存储引擎默认支持行锁。它是通过索引来实现行锁的,如果在操作过程中没有合适的索引,可能会导致行锁升级为表锁。例如,在一个用户表中,有主键索引(假设是user_id),当一个事务执行SELECT * FROM users WHERE user_id = 1 FOR UPDATE;时,InnoDB 会对user_id为 1 的行记录加行锁。这样其他事务可以对其他用户记录进行操作,而不会受到这个事务的影响。
    • 页锁(介于表锁和行锁之间)
      • 页锁是对存储引擎中的页(一般为固定大小的数据块,如 InnoDB 的页大小通常为 16KB)进行加锁。页锁的并发性能和管理开销介于表锁和行锁之间。它的使用相对较少,主要是因为在实际应用中,要么需要对整个表进行操作(适合用表锁),要么需要对具体的行进行操作(适合用行锁)。不过,在某些特定的场景下,页锁可能会发挥作用,例如在对一个数据页内的多个相关行进行批量操作时,页锁可以提供一定的性能优势。
  4. InnoDB 中的锁机制

    • 意向锁
      • 意向锁是 InnoDB 存储引擎自动添加的一种锁,用于表示事务在更高层次(表层次)上的锁意向。它分为意向共享锁(IS)和意向排他锁(IX)。当事务对表中的行加共享锁时,会自动对表加意向共享锁;当事务对表中的行加排他锁时,会自动对表加意向排他锁。
      • 意向锁的存在主要是为了方便事务在操作行锁时,能够快速判断表是否被其他事务锁定。例如,在一个复杂的多事务环境中,当一个事务想要对一个表中的行加锁时,通过检查表上是否有意向锁,可以快速确定是否有其他事务正在对该表中的行进行操作。如果表上有意向排他锁,那么新的事务就知道不能对表中的行随意加锁,需要等待锁的释放。
    • 记录锁(行锁)
      • 记录锁是对单个行记录进行锁定。在使用索引进行查询并更新数据时,InnoDB 通常会对满足条件的行记录加记录锁。例如,在一个有主键索引的表中,通过主键查询并修改一行数据时,会对该行加记录锁。记录锁的作用是确保在一个事务对某一行进行操作时,其他事务不能对同一行进行冲突操作。
      • 假设在一个员工信息表employees中有主键employee_id,当一个事务执行UPDATE employees SET salary = 5000 WHERE employee_id = 101;时,InnoDB 会对employee_id为 101 的行加记录锁,这样其他事务就不能同时修改这一行的工资信息。
    • 间隙锁(Gap Lock)
      • 间隙锁用于锁定一个范围,但不包括记录本身。它主要用于防止幻读现象,在可重复读(Repeatable Read)隔离级别下发挥重要作用。幻读是指一个事务在两次查询同一范围的数据时,第二次查询出现了第一次查询没有出现的新数据。
      • 例如,在一个成绩表scores中,有一个分数范围查询SELECT * FROM scores WHERE score BETWEEN 80 AND 90;,在可重复读隔离级别下,InnoDB 可能会对分数在 80 到 90 之间的间隙(不包括 80 和 90 这两个端点对应的记录,如果它们存在的话)加间隙锁。这样,当这个事务在操作过程中,其他事务就不能在这个间隙中插入新的记录,从而避免了幻读现象。
    • 临键锁(Next - Key Lock)
      • 临键锁是记录锁和间隙锁的组合。它既锁定一个记录,又锁定该记录前面的间隙。临键锁的范围是前开后闭区间,它在索引遍历过程中,用于防止其他事务在该区间插入新的数据,从而保证数据的一致性和隔离性。
      • 例如,在一个按照年龄排序的人员表persons中,索引是age。当一个事务执行SELECT * FROM persons WHERE age >= 30 AND age < 40;时,InnoDB 会对age大于等于 30 且小于 40 的记录以及这些记录前面的间隙加临键锁。这意味着其他事务不能在这个区间插入新的记录,同时也不能修改这个区间内已有的记录,确保了这个事务在这个区间内读取数据的一致性。
  5. 锁的使用场景和优化

    • 高并发读取场景
      • 在以读为主的高并发场景下,如新闻网站的文章查询、搜索引擎的索引数据查询等,共享锁是非常有用的。可以通过合理的索引设计,使得多个事务能够快速定位到需要读取的数据,并且加共享锁进行并发读取。例如,对于新闻文章表,可以根据文章类别、发布时间等建立索引,方便查询操作。
      • 同时,为了避免过多的锁竞争,可以采用一些缓存策略,如将经常访问的文章内容缓存到内存中,减少对数据库的直接查询和锁的使用。另外,还可以根据业务需求适当调整事务的隔离级别,在保证数据一致性的前提下,提高并发读取的性能。
    • 高并发写入场景
      • 在高并发写入场景下,如电商系统的订单处理、社交平台的用户信息更新等,充分利用行锁的优势至关重要。通过合理的数据库架构和索引设计,确保每个事务能够准确地对需要操作的行加行锁,避免不必要的表锁。例如,在电商订单表中,以订单编号作为主键,当处理不同订单时,通过主键索引对不同订单记录加行锁,实现高并发的订单处理。
      • 此外,可以采用乐观锁机制来替代部分排他锁的使用,提高并发性能。例如,在库存管理系统中,为每个库存记录添加一个版本号字段。当更新库存时,先查询出库存记录和对应的版本号,然后在更新时判断版本号是否一致,如果一致则更新库存并递增版本号,否则说明有其他事务已经更新了库存,需要重新查询和更新。
    • 长事务和锁等待
      • 长事务可能会导致锁长时间占用,从而影响其他事务的执行。为了尽量缩短事务的执行时间,避免长时间的锁等待,可以对 SQL 语句进行优化。例如,减少不必要的查询和更新操作,将复杂的事务拆分成多个小事务,提高事务的执行效率。
      • 同时,对业务逻辑进行合理设计,避免在事务中进行耗时的操作,如网络请求、文件读写等。另外,监控数据库的锁等待情况,及时发现和解决长时间的锁等待问题,也是优化数据库性能的重要环节。可以通过数据库的性能监控工具来查看锁等待的统计信息,如锁等待的次数、等待时间等,根据这些信息来调整数据库的配置和应用程序的逻辑。

标签:事务,记录,行锁,查询,概念,MySQL,操作,共享
From: https://blog.csdn.net/aaaa_1111111/article/details/144917484

相关文章

  • MySQL 的内部临时表
    在有些情况下,MySQLServer会在处理语句时创建内部临时表。用户无法直接控制这种情况何时发生。 通常情况下,内部临时表首先保留在内存中,以获得最佳查询性能。为避免内存分配过多,MySQL提供了参数,可用于设置内存限制。当达到该限制时,内部临时表就会溢出到磁盘存储。MySQL可能会......
  • 使用学生优惠创建 Azure Database for MySQL 数据库
    前言在此之前,你需要拥有一个已通过学生认证的Azure账户。关于通过Azure学生认证,网上已有大量教程,此处不再赘述。前些日子认证通过了Azure的学生认证,在部署此网站时发现Azure的B1s服务器用来部署网站同时部署数据库会出现内存不足的情况,同时想到Azure还为学生用户提......
  • MySQL高级篇之事务篇。
    文章目录1.数据库事务概述1.1存储引擎支持情况1.2基本概念1.3事务的ACID特性1.4事务的状态2.如何使用事务2.1显式事务2.2隐式事务2.3隐式提交数据的情况2.4使用举例1:提交与回滚2.5使用举例2:测试不支持事务的engine2.6使用举例3:SAVEPOINT3.事务隔离级别3.1......
  • 高性能MySQL(第4版)PDF、EPUB免费下载
    适读人群:不但适合数据库管理员(DBA)阅读,也适合开发人员参考学习。不管是数据库新手还是专家,相信都能从本书有所收获领域经典十年后全版更新||全面拥抱8.0||重磅剖析现代云数据库与大规模运维实践||中国首批DBA精琢翻译5大头部国产数据库创始人联合力荐电子版仅供预览,下载后24小......
  • 【MySQL】复合查询
    复合查询一、表的笛卡尔积1、介绍2、示例二、自连接1、介绍2、语法三、子查询1、介绍2、类型3、语法4、多行子查询运算符5、示例四、UNION和UNIONALL1、介绍2、注意3、语法4、示例五、表的连接查询1、介绍2、类型3、语法4、注意5、示例一、表的笛卡尔积1、介绍......
  • MySQL:一文弄懂时区&time_zone
    你还在被以下问题困扰吗:MySQL的安装规范中应该设置什么时区?JAVA应用读取到的时间和北京时间差了14个小时,为什么?怎么解决?已经运行一段时间的业务,修改MySQL的时区会影响已经存储的时间类型数据吗?迁移数据时会有导致时间类型数据时区错误的可能吗?…看完这篇文章,你......
  • MySQL备份脚本.241217
    MYSQL备份,每天全量备份(排除由于GTID的缘故造成恢复问题的系统库),然后通过Gzip进行压缩。#!/bin/bash#DEFINEVARIABLESBACKUPUSER=rootBACKUPPASS=root密码BACKUPPORT=mysql端口#BACKUPSOCKET=/home/data/$BACKUPPORT/logs/mysql.sockBACKUPIP=localhostMYSQL=/usr/local......
  • RockyLinux 9.5 MySQL5.7_二进制方式+jdk1.8+tomcat9+jpress
    安装MySQL5.7#cd/opt#yuminstall-ywget#wgethttps://cdn.mysql.com/archives/mysql-5.7/mysql-5.7.10-linux-glibc2.5-x86_64.tar.gz#tar-xvfmysql-5.7.10-linux-glibc2.5-x86_64.tar.gz-bash:tar:commandnotfound#yuminstall-ytar#tar-xvfmysql-5.7.10......
  • 欧拉OpenEuler安装MySQL8.241227
    1.安装mysqltar-xvfmysql-8.0.21-linux-glibc2.12-x86_64.tarmvmysql-8.0.21-linux-glibc2.12-x86_64/usr/local/mysql2.配置mysqlvim/etc/my.cnf[client]default-character-set=utf8mb4[mysqld]#nd-address=0.0.0.0port=3306user=mysqlbasedir=/usr/local/m......
  • 【基础篇重点】六、MySQL表的增删查改
    文章目录前言Ⅰ.创建新数据1、`insert`语句2、插入否则更新--替换3、替换--`replace`Ⅱ.检索数据1、`select`语句①全列查询②指定列查询③查询字段为表达式④为查询结果指定别名`as`⑤结果去重`distinct`2、`where`条件......