一文理解MySQL的For Update行级锁

这篇具有很好参考价值的文章主要介绍了一文理解MySQL的For Update行级锁。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言


💡 作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。
👉
🎖️ CSDN实力新星,社区专家博主
👉
🔔 博客主页:https://blog.csdn.net/Long_xu


一、MySQL的For Update简介

For update是MySQL中用于实现行锁的一种语法,其主要作用是在SELECT查询语句中加上FOR UPDATE子句,以保证查询结果集中的每一行都被锁定,避免其他事务对这些行进行修改。具体语法如下:

SELECT ... FROM table_name WHERE ... FOR UPDATE;

在执行For update语句时,MySQL会首先获取表级共享锁,然后再根据WHERE条件锁定符合条件的行。锁定的范围包括了WHERE条件筛选出来的所有行,即使有些行并不满足WHERE条件。

需要注意的是,For update语句会将锁定的行一直锁定到事务结束,因此在使用时需要考虑是否会导致死锁的问题,并尽量缩小锁定的范围。同时,对于InnoDB存储引擎的表,可以使用行级锁和间隙锁来提高并发性能。

1.1、For Update的作用

"For Update"是一种SQL语句,它的作用是在查询过程中锁定数据行,防止其他事务对这些数据进行修改操作。使用"For Update"可以保证当前事务对被锁定的数据具有排他性,并且能够避免产生并发问题。"For Update"适用于需要修改或者删除数据的场景,例如在一个订单系统中,如果多个用户同时尝试对同一个订单进行修改操作,就可以使用"For Update"方式来避免冲突。

1.2、For Update与其他锁定方式的区别

  1. For Update是一种排它锁定方式,只有被锁定的行才能进行修改操作。而共享锁定方式允许多个事务同时读取同一行数据,但是不允许对其进行修改。
  2. For Update锁定方式可以避免出现脏读、不可重复读和幻读等并发问题,因为它会在读取某一行数据时将其锁定,直到事务结束或提交之前才释放锁定。
  3. For Update锁定方式可能会导致死锁问题,因为多个事务可能会互相等待对方释放锁定。而其他锁定方式如共享锁定则不存在这个问题。
  4. For Update锁定方式的性能较差,因为它需要在读取数据时进行锁定操作,增加了系统的开销。而其他锁定方式如共享锁定则没有这个问题。

二、For Update的语法

2.1、SELECT语句的基本语法

SELECT column1, column2, ... FROM table_name WHERE condition;

其中,column1、column2等为要查询的列名,用逗号分隔;table_name为要查询的表名;condition为查询条件,可选。

2.2、mysql如何开启事务和提交事务?

MySQL中使用START TRANSACTION命令来开启一个事务,使用COMMIT命令来提交事务。开启事务后,在数据库中所做的所有更改都不会立即写入磁盘,而是被缓存到内存中。只有在事务提交时,这些更改才会被保存到磁盘上。

下面是一个简单的示例,演示如何开启并提交一个事务:

-- 开启事务
START TRANSACTION;

-- 执行一系列SQL语句,对数据进行修改
INSERT INTO my_table (col1, col2) VALUES ('value1', 'value2');
UPDATE my_table SET col3 = 'new_value' WHERE col1 = 'value1';

-- 提交事务
COMMIT;

使用START TRANSACTION命令开启了一个事务,并在之后执行了一系列对数据进行修改的SQL语句。最后使用COMMIT命令提交了事务,从而将所有的修改操作保存到了磁盘上。

如果需要取消事务所做的修改操作,可以使用ROLLBACK命令来回滚事务。例如:

-- 开启事务
START TRANSACTION;

-- 执行一系列SQL语句,对数据进行修改
INSERT INTO my_table (col1, col2) VALUES ('value1', 'value2');
UPDATE my_table SET col3 = 'new_value' WHERE col1 = 'value1';

-- 回滚事务
ROLLBACK;

在上述示例中,使用ROLLBACK命令回滚了事务,从而取消了所有已经执行的修改操作。

2.3、使用For Update进行数据锁定

使用For Update需要注意以下几点:

  1. For Update只能应用于SELECT语句中。
  2. 对于使用了For Update的SELECT语句,只有当事务提交或回滚时,所加的锁才会被释放。
  3. 在使用For Update时,要确保事务的隔离级别为Serializable级别,因为只有这个级别能够保证数据的完整性和一致性。

下面是一个使用For Update进行数据锁定的示例:

START TRANSACTION;

SELECT * FROM table_name WHERE id = 1 FOR UPDATE;

UPDATE table_name SET column_name = 'new_value' WHERE id = 1;

COMMIT;

先使用SELECT语句来选取待更新的行,并在其后添加FOR UPDATE关键字,从而将该行数据进行锁定。然后再执行UPDATE语句来更新该行数据。最后通过COMMIT确认事务完成,从而释放锁定。

三、如何使用For Update

3.1、For Update的应用场景

  1. 数据库更新:当数据库中某些记录需要进行修改、删除或插入时,可以使用For Update锁定这些记录,以确保数据操作的正确性和一致性。
  2. 并发控制:在并发访问情况下,多个线程可能会同时读取和写入同一份数据,使用For Update可以避免并发问题,保证数据的完整性和准确性。
  3. 事务处理:在事务中,For Update可以确保对共享资源的互斥访问,防止出现数据不一致的情况。
    缓存更新:使用For Update可以在缓存中更新数据,保证在多个进程或线程中操作缓存时的数据一致性。
  4. 悲观锁控制:For Update是一种悲观锁控制方法,可以确保在对共享资源进行操作前,先将其锁定,以防止其他线程对其修改。

3.2、使用案例分析

(1)并发读取和更新操作。

假设有一个银行账户表,其中包含账户余额。为了保证并发操作在更新账户余额时不会出现问题,可以使用FOR UPDATE语句锁定数据行。

例如,以下SQL查询会对指定的账户进行锁定:

SELECT balance FROM accounts WHERE account_number = '12345' FOR UPDATE;

这将锁定具有帐户号码“12345”的帐户行,并且在事务提交之前,其他事务将无法修改该行。接下来,可以更新余额,例如:

UPDATE accounts SET balance = balance - 100 WHERE account_number = '12345';

在此示例中,“12345”账户的余额将被减少100元。在提交事务之后,其他事务才有机会访问该行并进行更新。

(2)多个事务同时访问同一条记录。

使用For Update语句可以在多个事务同时访问同一条记录时实现加锁,保证数据的一致性。

在MySQL中,For Update语句可以在SELECT语句中使用,如:

SELECT * FROM table_name WHERE id=1 FOR UPDATE;

这条语句会锁定id为1的记录,其他事务需要等待该事务释放锁才能对该记录进行操作。

当有多个事务同时访问同一条记录时,只有一个事务能够获得锁,其他事务需要等待。如果获得锁的事务没有及时释放锁,则其他事务可能会发生死锁现象。

需要注意的是,在使用For Update语句时应尽量控制事务的范围,避免锁定过多的记录,影响数据库的并发性能。

(3)防止脏读取和不可重复读取。

假设有一个银行账户表,其中包含账户名、余额和最近更新时间这三个字段。现在需要对某个账户进行转账操作,并且要求转账过程中不能出现脏读取和不可重复读取的情况。

使用For Update可以实现这一要求。For Update是MySQL提供的一种行级锁定机制,它可以锁定查询结果集中的指定行,从而避免其他事务对这些行进行修改或删除操作。

下面是一个示例代码,假设要将账户A中的100元转账给账户B:

START TRANSACTION;

SELECT balance FROM accounts WHERE account_name = 'A' FOR UPDATE;

UPDATE accounts SET balance = balance - 100 WHERE account_name = 'A';
UPDATE accounts SET balance = balance + 100 WHERE account_name = 'B';

COMMIT;

在上述代码中,首先使用SELECT语句查询账户A的余额,并使用FOR UPDATE子句对其进行锁定。这意味着在当前事务未提交之前,其他事务无法对账户A的余额进行修改或删除操作,从而避免了脏读取和不可重复读取的情况。接下来,使用两个UPDATE语句分别将账户A的余额减少100元,将账户B的余额增加100元,并在最后进行事务提交。

需要注意的是,使用For Update会对性能产生一定的影响,因此应该谨慎使用。在实际应用中,可以根据具体情况进行优化和调整。

四、For Update的注意事项

4.1、For Update的局限性

For Update虽然可以解决部分并发问题,但也存在一定的局限性。

  1. For Update只能用于InnoDB引擎。如果使用MyISAM等其他引擎,无法使用For Update。
  2. For Update会对查询结果集中的行进行锁定,这意味着其他事务无法对这些行进行修改或删除操作。如果锁定时间过长,可能会导致其他事务出现阻塞,从而影响系统的并发性能。
  3. 如果在一个事务中多次使用For Update语句锁定同一行,则后面的For Update语句可能会被前面的For Update语句所覆盖。因此,在使用For Update时应该谨慎考虑锁定的粒度,尽量避免对同一行进行多次锁定操作。
  4. 在MySQL 8.0版本之前,For Update只能锁定整个表、整个分区或整个索引。如果要锁定某个特定的行,需要使用WHERE子句来指定条件。但是,这种方式会增加锁定的粒度,可能会导致更多的阻塞和性能问题。

4.2、不当使用For Update可能导致的问题

  1. 死锁:如果多个事务同时使用For Update锁定相同的资源,可能会导致死锁。
  2. 性能问题:使用For Update会锁定相应的行,这可能会影响并发性和性能。
  3. 数据一致性问题:在事务中使用For Update锁定行时,如果在锁定期间其他事务对相同的数据进行了更新,则当前事务可能会读取到已过时的数据。
  4. 阻塞问题:如果一个事务长时间持有For Update锁,其他事务将无法访问相应的资源,这可能会导致阻塞问题。
  5. 安全问题:当使用For Update时,必须小心不要将代码中的所有查询都添加上锁,否则可能会导致安全问题。例如,如果一个查询返回敏感信息,但未加锁,则可能会导致信息泄漏。

4.3、For Update一定只锁行吗?

MySQL的FOR UPDATE语句只会对查询结果集中的行进行行锁,其他事务无法修改被锁定的行。但需要注意的是,在多表查询时,如果没有正确地使用JOIN操作或者没有设置正确的索引,可能会导致表级锁定而不是行级锁定。

比如有两个表A和B,A表中有id和name字段,B表中有id和age字段。现在要查询A表中所有名字为“Tom”的记录,并更新对应的B表中的年龄。

如果使用如下的SQL语句:

SELECT * FROM A WHERE name = 'Tom' FOR UPDATE;
UPDATE B SET age = 30 WHERE id = ?;

如果A表中的name字段没有索引,那么MySQL就会对整个A表进行表级锁定,而不是对查询结果集中的行进行行级锁定。这样,即使只有一条记录满足条件,也会导致其他事务无法访问A表,从而影响系统的并发性能。因此,在使用FOR UPDATE时,需要注意表的索引情况,尽量避免表级锁定的出现。

五、总结

5.1、理解For Update的优缺点

For Update是一种SQL语句,用于锁定指定的行或表,以保证在事务中其他用户不能修改这些数据。

优点:

  1. 数据的完整性:使用For Update可以避免并发操作导致数据不一致的问题。
  2. 提高效率:通过锁定数据,可以减少多个事务同时对同一行数据进行修改的情况,从而提高了查询和更新的效率。
  3. 简化代码:通过使用For Update,开发人员可以简化代码,并减少手动处理并发操作带来的风险。

缺点:

  1. 并发性降低:使用For Update会阻塞其他事务对锁定的数据进行修改,因此可能会导致并发性降低。
  2. 死锁风险:如果多个事务之间互相等待对方释放锁,则可能会出现死锁的情况。
  3. 内存开销:For Update需要占用一定的内存资源,当并发量很大时,可能会占用更多的内存资源,从而影响系统的稳定性。

5.2、合理使用For Update,提升数据库性能

For Update是一种数据库锁定机制,用来保护数据的一致性和完整性。在进行修改操作时,For Update会锁定相应记录,防止其他事务同时修改同一条数据造成数据不一致。

合理使用For Update可以提升数据库性能,主要表现在以下几个方面:

  1. 减少数据库死锁情况:使用For Update可以有效地避免多个事务同时对同一条数据进行修改而造成的死锁问题。
  2. 提高并发处理能力:For Update只会锁定相应的记录,而不是整个表,因此可以在保证数据一致性的前提下支持更多的并发操作。
  3. 缩短事务执行时间:使用For Update可以减少事务的回滚次数,缩短事务的执行时间,从而提升数据库的性能。

但是,过度使用For Update也会带来一些副作用,如增加数据库的锁定和等待时间、降低数据库的并发处理能力等。因此,在使用For Update时需要根据具体情况进行合理的优化和调整。
一文理解MySQL的For Update行级锁文章来源地址https://www.toymoban.com/news/detail-500236.html

到了这里,关于一文理解MySQL的For Update行级锁的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MySQL中锁的简介——表级锁-表锁

    2024年02月15日
    浏览(35)
  • Invalid ON UPDATE clause for update_time column

    问题所在: 我在导入sql脚本的时候,没有成功导入,报的是Invalid ON UPDATE clause for ‘update_time’ column,在更新的时候表创建失败,于是我就查看了该错误,才发现我导入的sql脚本是高本版转储的sql脚本,我的 mysql版本比较低 , 所以会有这个错误 。 解决方案: 把原本的mysq

    2024年02月11日
    浏览(33)
  • 由select for update锁等待问题引发的深入思考

    关于 MySQL 的加锁机制,其实十分复杂,不同的隔离级别,是否是主键或索引,锁的粒度等等。很多工作了很多年的 MySQL DBA 也不能把各种加锁场景一一讲清楚。有时候一个简单的锁等待场景都值得深入研究,大家更多的是知其然而不知其所以然。本文介绍的是一个很常见的锁

    2024年03月09日
    浏览(38)
  • 深入理解Linux中的“sudo apt-get update“命令

    在Linux操作系统中,sudo apt-get update 是一个常用的命令,用于更新系统中可用软件包的信息。这个命令允许用户获取最新的软件包列表和更新信息,以确保系统上的软件保持最新状态。在本文中,我们将详细解释sudo apt-get update命令的用法和工作原理。 目录 1.什么是 \\\"sudo apt-g

    2024年02月05日
    浏览(51)
  • 【git】idea使用update提示Can‘t Update No tracked branch configured for branch master or the branch doe...

    当使用idea拉取最新代码进行更新时,提示信息如下 查看提示信息 提示中已经给出了例子: 我的分支是在origin/master。于是如下:打开git命令窗口 输入:git branch --set-upstream-to=origin/master/分支名 然后push下就行了

    2024年02月11日
    浏览(50)
  • for循环中循环一次提交一次 insert update 关闭事务 spring springboot mybatis

     在方法上直接加如下注解: 在测试的时候,有时候会希望在for循环中,代码循环一次就提交一次事务。 最简单的方式,就是关闭事务,不需要事务。添加注解如下: 如果说是真的在生产上有这样的需要,每循环一次就提交事务,那就需要手动控制事务了。 需要这几行代码

    2024年02月07日
    浏览(47)
  • 关于 MySQL 中 Update 使用

    Update 是 SQL 中用于更新表格中已有记录的命令。通过使用 Update 命令,您可以更新表格中的一行或多行记录,并根据需要更改它们的值。在执行 Update 命令时,务必保证更新的数据符合表格中已有的约束条件,否则将无法更新记录。 在 MySQL 中,Update 命令的基本语法如下: U

    2024年02月16日
    浏览(32)
  • 解决Data too long for column ‘xxx‘ at row 1问题以及深入理解mysql的字符串数据类型(char,varchar,enum,text,longtext...)

    今天在测试环境新增数据时,报出如是错误: Data too long for column \\\'apply_service_type\\\' at row 1 。 为了复现这个问题,我特地在本地数据库中增加如下 test 表:

    2023年04月17日
    浏览(49)
  • Mysql——update更新数据的方式

    注:文章参考: MySQL 更新数据 不同条件(批量)更新不同值_update批量更新同一列不同值-CSDN博客 文章浏览阅读2w次,点赞20次,收藏70次。一般在更新时会遇到以下场景:1.全部更新;2.根据条件更新字段中的某部分内容;3.根据不同的条件更新不同的值,以下是几种场景中常用

    2024年04月26日
    浏览(35)
  • 【MYSQL篇】Update语句原理详解

    前面的文章我们已经对MySQL的查询语句的执行流程进行了说明,感兴趣的可以去看看: 【MySQL篇】Select语句原理详解 本篇文章我们来聊聊 MySQL更新语句的执行原理。更新流程和查询流程有什么不同呢? 基本流程也是一致的,也就是说,它也要经过解析器、优化器的处理,最后

    2024年02月10日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包