数据库高并发请求,如何保证数据完整性?详解MySQL/InnoDB的加锁

本文是对mysql/innodb中,乐观锁、悲观锁、共享锁、排它锁、行锁、表锁、死锁概念的理解,这些在面试中也经常遇到,如数据库高并发请求,如何保证数据完整性?今天我查阅资料进行了mysql/innodb中加锁知识点的汇总,这样也会大家就不会感觉很繁琐和杂乱了,觉得有用的话就继续分享吧。apache php mysql

注:MySQL是一个支持插件式存储引擎的数据库系统。本文下面的所有介绍,都是基于InnoDB存储引擎,其他引擎的表现,会有较大的区别。

存储引擎查看

MySQL给开发者提供了查询存储引擎的功能,我这里使用的是MySQL5.6.4,可以使用:

SHOW ENGINES

begin!

乐观锁

用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加1。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。

举例

1、数据库表设计

三个字段,分别是id,value、version

select id,value,version from TABLE where id=#{id}

2、每次更新表中的value字段时,为了防止发生冲突,需要这样操作

update TABLEset value=2,version=version+1where id=#{id} and version=#{version};

悲观锁

与乐观锁相对应的就是悲观锁了。悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作,这点跟java中的synchronized很相似,所以悲观锁需要耗费较多的时间。另外与乐观锁相对应的,悲观锁是由数据库自己实现了的,要用的时候,我们直接调用数据库的相关语句就可以了。

说到这里,由悲观锁涉及到的另外两个锁概念就出来了,它们就是共享锁与排它锁。共享锁和排它锁是悲观锁的不同的实现,它俩都属于悲观锁的范畴。

使用,排它锁 举例

要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。

我们可以使用命令设置MySQL为非autocommit模式:

set autocommit=0;# 设置完autocommit后,我们就可以执行我们的正常业务了。具体如下:# 1. 开始事务begin;/begin work;/start transaction; (三者选一就可以)# 2. 查询表信息select status from TABLE where id=1 for update;# 3. 插入一条数据insert into TABLE (id,value) values (2,2);# 4. 修改数据为update TABLE set value=2 where id=1;# 5. 提交事务commit;/commit work;

共享锁

共享锁又称读锁 read lock,是读取操作创建的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。

如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获得共享锁的事务只能读数据,不能修改数据

打开第一个查询窗口

begin;/begin work;/start transaction;  (三者选一就可以)SELECT * from TABLE where id = 1  lock in share mode;

然后在另一个查询窗口中,对id为1的数据进行更新

update  TABLE set name="www.souyunku.com" where id =1;

此时,操作界面进入了卡顿状态,过了超时间,提示错误信息

如果在超时前,执行 commit,此更新语句就会成功。

[SQL]update  test_one set name="www.souyunku.com" where id =1;[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

加上共享锁后,也提示错误信息

update  test_one set name="www.souyunku.com" where id =1 lock in share mode;
[SQL]update  test_one set name="www.souyunku.com" where id =1 lock in share mode;[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'lock in share mode' at line 1

在查询语句后面增加 LOCK IN SHARE MODE,Mysql会对查询结果中的每行都加共享锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞。其他线程也可以读取使用了共享锁的表,而且这些线程读取的是同一个版本的数据。

加上共享锁后,对于update,insert,delete语句会自动加排它锁。

排它锁

排他锁 exclusive lock(也叫writer lock)又称写锁

排它锁是悲观锁的一种实现,在上面悲观锁也介绍过

若事务 1 对数据对象A加上X锁,事务 1 可以读A也可以修改A,其他事务不能再对A加任何锁,直到事物 1 释放A上的锁。这保证了其他事务在事物 1 释放A上的锁之前不能再读取和修改A。排它锁会阻塞所有的排它锁和共享锁

读取为什么要加读锁呢:防止数据在被读取的时候被别的线程加上写锁,

使用方式:在需要执行的语句后面加上for update就可以了

行锁

行锁又分共享锁排他锁,由字面意思理解,就是给某一行加上锁,也就是一条记录加上锁。

注意:行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁。

怪兽AI数字人 怪兽AI数字人

数字人短视频创作,数字人直播,实时驱动数字人

怪兽AI数字人 44 查看详情 怪兽AI数字人

共享锁:

名词解释:共享锁又叫做读锁,所有的事务只能对其进行读操作不能写操作,加上共享锁后在事务结束之前其他事务只能再加共享锁,除此之外其他任何类型的锁都不能再加了。

SELECT * from TABLE where id = "1"  lock in share mode;  结果集的数据都会加共享锁

排他锁:

名词解释:若某个事物对某一行加上了排他锁,只能这个事务对其进行读写,在此事务结束之前,其他事务不能对其进行加任何锁,其他进程可以读取,不能进行写操作,需等待其释放。

select status from TABLE where id=1 for update;

可以参考之前演示的共享锁,排它锁语句

由于对于表中,id字段为主键,就也相当于索引。执行加锁时,会将id这个索引为1的记录加上锁,那么这个锁就是行锁。

表锁

如何加表锁

innodb 的行锁是在有索引的情况下,没有索引的表是锁定全表的.

Innodb中的行锁与表锁

前面提到过,在Innodb引擎中既支持行锁也支持表锁,那么什么时候会锁住整张表,什么时候或只锁住一行呢?
只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!

在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。

行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁。行级锁的缺点是:由于需要请求大量的锁资源,所以速度慢,内存消耗大。

死锁

死锁(Deadlock) 
所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。

解除正在死锁的状态有两种方法:

第一种

1.查询是否锁表

show OPEN TABLES where In_use > 0;

2.查询进程(如果您有SUPER权限,您可以看到所有线程。否则,您只能看到您自己的线程)

show processlist

3.杀死进程id(就是上面命令的id列)

kill id

第二种

1:查看当前的事务

SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

2:查看当前锁定的事务

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

3:查看当前等锁的事务

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;

杀死进程

kill 线程ID

如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:

(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

虽然不能完全避免死锁,但可以使死锁的数量减至最少。将死锁减至最少可以增加事务的吞吐量并减少系统开销,因为只有很少的事务回滚,而回滚会取消事务执行的所有工作。由于死锁时回滚而由应用程序重新提交。

下列方法有助于最大限度地降低死锁:

(1)按同一顺序访问对象。
(2)避免事务中的用户交互。
(3)保持事务简短并在一个批处理中。
(4)使用低隔离级别。
(5)使用绑定连接。

end!

相关文章:

数据库并发事务控制 二:mysql数据库锁机制

Mysql数据库锁定机制详细介绍

相关视频:

数据库设计那些事

以上就是数据库高并发请求,如何保证数据完整性?详解MySQL/InnoDB的加锁的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/382901.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月6日 12:13:14
下一篇 2025年11月6日 12:14:16

相关推荐

  • OAuth认证后的用户数据持久化与安全会话管理

    本教程将深入探讨OAuth2认证流程中,如何高效且安全地处理从身份提供商获取的用户数据,并将其持久化到数据库。我们将介绍使用UPSERT操作来避免数据重复和竞态条件,并详细阐述如何通过配置安全的HTTP-only会话Cookie来建立和维护用户会话,以抵御常见的Web安全威胁,确保用户认证体验的流畅…

    2025年12月16日
    000
  • Go语言database/sql包中处理动态SQL IN 查询的实践指南

    本文详细介绍了在Go语言中使用database/sql包执行动态SQL IN查询的通用方法。针对IN子句无法直接接受切片作为参数的问题,教程重点阐述了如何通过动态生成占位符?并配合可变参数传递切片元素来构建安全高效的查询,并提供了完整的代码示例和注意事项。 在go语言的database/sql包中,…

    2025年12月16日
    000
  • OAuth2认证后用户数据存储与会话安全指南

    本文旨在提供OAuth2认证后处理用户数据持久化和会话管理的最佳实践。我们将探讨如何将OAuth返回的用户数据安全地存储到数据库,推荐使用事务性的UPSERT操作来处理用户存在性检查与插入/更新。同时,文章还将详细阐述如何通过配置安全的HTTP-only会话Cookie来建立和维护用户会话,并强调H…

    2025年12月16日
    000
  • OAuth响应处理与安全会话管理:数据库集成与Cookie最佳实践

    本教程深入探讨了OAuth2认证流程结束后,如何安全高效地处理用户数据并建立会话。文章首先介绍了将OAuth提供者返回的用户数据存储到数据库的最佳实践,重点讲解了原子性的UPSERT操作以避免数据冗余和竞态条件。随后,详细阐述了基于Cookie的会话管理策略,强调了使用HTTPS、Secure、Ht…

    2025年12月16日
    000
  • Go database/sql 包查询结果行数精确判断与首行数据获取

    本文深入探讨Go语言中database/sql包在数据库查询时,如何精确判断返回结果的行数(零行、单行或多行),并安全地获取首行数据。针对QueryRow的局限性,文章提供了一个通用的自定义函数方案,利用db.Query和*sql.Rows的特性,实现对查询结果的细粒度控制,同时强调了错误处理和资源…

    2025年12月16日
    000
  • OAuth2集成:用户数据持久化与安全会话管理指南

    本文旨在探讨OAuth2认证流程结束后,如何高效且安全地处理用户数据持久化与会话管理。我们将重点介绍数据库中用户数据的“存在则更新,不存在则插入”(UPSERT)策略,并深入讲解如何利用HTTPS和安全、HttpOnly的Cookie来建立健壮的用户会话,以确保用户体验和系统安全。 1. OAuth…

    2025年12月16日
    000
  • 在Go语言中处理SQL IN 子句的动态参数绑定

    本文旨在解决Go语言database/sql包中,如何将动态切片(slice)作为IN查询条件参数的问题。由于db.Query无法直接将切片展开为多个占位符,我们将探讨一种通用且安全的解决方案,通过动态生成SQL语句中的占位符并结合interface{}类型转换来实现,确保代码的灵活性和防止SQL注…

    2025年12月16日
    000
  • OAuth 响应处理与安全会话管理实践指南

    本教程旨在指导开发者如何高效且安全地处理 OAuth2 认证流程中获取的用户数据,并将其存储至数据库。文章将重点介绍采用 UPSERT 语句进行数据更新或插入的最佳实践,同时详细阐述如何利用安全 Cookie(如 Secure、HttpOnly 和 Path 选项)构建健壮的用户会话管理机制,规避潜…

    2025年12月16日
    000
  • Go语言database/sql:高效构建和执行带有可变参数的IN查询

    在Go语言中,使用database/sql包执行带有可变参数列表的IN查询时,直接传入切片作为单个占位符是无效的。本文将详细介绍一种通用的解决方案,通过动态生成SQL语句中的占位符(问号),并将切片元素展开为独立的参数传递给db.Query方法,从而优雅地处理IN子句中的可变值集合,并讨论相关注意事…

    2025年12月16日
    000
  • Golang如何实现自动化备份与恢复

    Go语言适合构建自动化备份与恢复系统,其核心是通过调用系统命令或API实现数据备份与恢复。1. 文件备份可使用os和io包复制文件,数据库备份可通过mysqldump等工具或驱动导出;2. 使用robfig/cron库设置定时任务,如每日2点执行备份,并结合systemd或Kubernetes管理任…

    2025年12月16日
    000
  • 如何使用Golang测试数据库操作

    使用事务回滚确保测试隔离,通过传入*sql.Tx实现数据操作函数的可测试性,结合sqlmock模拟SQL验证逻辑,保证测试可重复且无副作用。 测试数据库操作在 Golang 中是确保数据层逻辑正确的重要环节。关键在于隔离真实环境、使用事务控制以及合理模拟数据。以下是具体实践方法。 使用测试数据库或事…

    2025年12月16日
    000
  • Go语言连接MySQL数据库:权限配置与常见问题解决指南

    本文详细探讨Go语言连接MySQL数据库时遇到的常见问题,特别是“Access denied”错误和数据查询无结果的情况。核心问题在于MySQL用户权限配置不当,未能授权通过TCP连接。文章提供了详细的MySQL用户权限设置步骤,并结合Go语言的database/sql接口和go-sql-drive…

    2025年12月16日
    000
  • Go语言连接MySQL数据库:权限配置与常见问题解析

    本文详细介绍了在Go语言中如何连接MySQL数据库,重点解决了常见的“Access Denied”权限错误以及查询结果为空的问题。通过使用go-sql-driver/mysql驱动,文章提供了详细的代码示例,并强调了MySQL用户权限配置的关键性,指导读者正确设置用户权限以确保Go应用程序能顺利访问…

    2025年12月16日
    000
  • Go语言生态系统:Java开发者工具链指南

    本文旨在为Java开发者提供一份Go语言开发生态系统的全面指南,涵盖集成开发环境、依赖管理、持续集成工具以及常用库的对应方案。我们将探讨Go语言在这些方面的独特实践,帮助开发者平滑过渡并高效利用Go的优势,从而提升开发效率和项目管理能力。 1. 集成开发环境(IDE)与代码编辑器 对于习惯了ecli…

    2025年12月16日
    000
  • Go语言Web应用用户认证系统构建指南

    Go语言生态系统在用户认证方面不同于Python等语言的成熟框架,它不提供一站式解决方案。本文将指导读者如何利用Go的标准库及精选的第三方包,如html/template、database/sql、golang.org/x/crypto/bcrypt和github.com/gorilla/sessi…

    2025年12月16日
    000
  • 从Java生态到Go语言:核心工具与实践指南

    本文旨在为拥有Java背景的开发者提供一份Go语言生态系统的全面指南,涵盖集成开发环境(IDE)、依赖管理、持续集成(CI/CD)工具以及常用库的对等方案。我们将探讨Go语言特有的工具和实践,帮助开发者平稳过渡并高效利用Go的简洁与强大。 Go语言开发环境与工具链 对于习惯了java强大ide的开发…

    2025年12月16日
    000
  • Go语言开发生态:Java背景开发者的迁移指南

    本文旨在为具备Java开发经验的工程师提供一份Go语言生态的概览与迁移指南。我们将探讨Go语言在集成开发环境、依赖管理、持续集成工具以及常用库方面的对应解决方案,帮助开发者平滑过渡,并理解Go语言特有的开发哲学与实践。 1. 开发环境与集成开发工具 (IDEs and Development Env…

    2025年12月16日
    000
  • Go Web应用用户认证实践:模块化构建与关键库解析

    Go语言在用户认证方面没有像Python那样提供开箱即用的成熟框架,而是倡导通过组合现有库来构建。本文将指导读者如何利用Go标准库及精选第三方包,从登录页面处理、用户数据存储、密码安全哈希到会话管理,模块化地实现一个安全、可扩展的用户认证系统。我们将探讨html/template、net/http、…

    2025年12月16日
    000
  • Go语言用户认证实现指南:模块化方法与核心库实践

    Go语言生态系统不像Python的Django或Flask那样提供“开箱即用”的完整用户认证框架。本文将深入探讨如何在Go标准Web服务器中,通过组合使用Go官方库及社区成熟的第三方库,从零开始构建一个安全、可扩展的用户认证系统,涵盖登录页面处理、用户数据存储、密码安全哈希与会话管理等核心环节。 G…

    2025年12月16日
    000
  • Go语言中处理SQL查询与interface{}参数的技巧与陷阱

    本文探讨Go语言中将interface{}类型参数传递给SQL查询时遇到的常见问题,特别是当数据库驱动(如mymysql)未能正确解析标准占位符时。我们将深入分析错误原因,并提供使用printf风格格式化字符串作为解决方案,同时强调其潜在的安全风险,并给出最佳实践建议。 Go语言与SQL查询参数绑定…

    2025年12月16日
    000

发表回复

登录后才能评论
关注微信