浅尝数据库并发控制

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS SQL Server,基础系列 2核4GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介:         数据库是一个共享资源,可以供多个用户使用。然而,对于大多数程序员来说,单处理机系统是我们接触最多的系统,运行在其上的数据库事务也并非真正意义上的并行,实际上它是这些并行事务的并行操作轮流交叉运行,这种并行执行方式称为交叉并发方式(Interleaved Concurrency),这样可以减少处理机的空闲时间,提高系统的效率。而在多处理机系统中,每个处理机可以运行一个事务,多

        数据库是一个共享资源,可以供多个用户使用。然而,对于大多数程序员来说,单处理机系统是我们接触最多的系统,运行在其上的数据库事务也并非真正意义上的并行,实际上它是这些并行事务的并行操作轮流交叉运行,这种并行执行方式称为交叉并发方式(Interleaved Concurrency),这样可以减少处理机的空闲时间,提高系统的效率。而在多处理机系统中,每个处理机可以运行一个事务,多个处理机可以同时运行多个事务,实现真正意义上的并行运行,而这种并行执行方式,我们称之为同时并行方式(Simultaneous Concurrency)。在这篇文中,我将自己在开发中遇到的数据库并发控制的程序设计经验介绍给大家(当然了,这里我用的是单处理机,并且抛弃具体的编程语言,只从SQL上进行详细讲解),希望能够抛砖引玉。

       我们都知道,事务是并发控制的基本单位,保证事务的ACID(Atomicity,Consistency,Isolation,Durability)特性是事务处理的重要任务。而程序员在具体的程序设计中,又是如何做到的呢?市面上目前流行的数据库书籍或者是针对某种编程语言的项目实践指南,都只是从理论上对我们进行一番说教,可真正到了实战中,往往三言两语,整的我们大家往往丈二和尚摸不着头脑。天花乱坠猛砍一顿,可是实际应用中又是如何呢,在这,我将带领大家一起分享我的经验,一起进入神秘的并发控制之旅吧!(对了,在这,我用的数据库主要是MySQL,并配之以MS SQL Server,Oracle,PostgreSQL比较讲解!)

       仔细分析并发操作给数据库带来的不一致,我将其分为三类(注意,大家也许见过不同的分类,但万变不离其宗,在这,也是为了后面文章叙述方便,按照自己的理解将其归类):第一类,丢失修改;第二类,不可重复读;第三类,脏读。下面,我将结合实例,带大家一起看看具体的数据库操作中,这些不一致现象是如何产生的,再将应对措施介绍给大家。


        如上图,我们简单地模拟一下火车站售票系统的数据库,表seat只包含三列,分别代表座位编号,座位位置,座位订票人。

        现在我们来看看什么是丢失修改(Lost Update),假设订票员X查看哪个座位空闲,这时,她开启一个事务操作,如下所示:


       在此期间,订票员Y处理了另一个事务,他发出了相同的查询,并得到了相同的响应,马上,他决定订下座位1:


      订票员X动作只比Y略微慢了一点,几秒钟之后,她开始订票:

     

        怎么样,从图中,我们很明显看到订票员Y做的订票操作丢失了,这就是所谓的丢失修改。当然,这是一个严重的编程错误。那么我们怎么解决这种数据库操作带来的不一致呢?就目前,主流的解决方案有两种,一种就是将数据库事务隔离级别设置到Serializable,当然,这种方式我是不推荐使用的,原因很简单,隔离级别指明了在事务中如何获得锁(恩,什么是锁?稍安勿躁,等会我会详细告知),隔离级别越高,带来的性能损失越大,这个在大数据集,高并发应用中,将会体现的淋漓尽致。第二种就是所谓的悲观锁机制,在Oracle,MySQL和PostgreSQL中,你可以使用如下语句:



         在MS SQL Server中,语句略有不同,如下:

        在这种情况下,订票员X先运行select…for update ,锁住了所有可用座位,这时,订票员Y运行select… for update时,被强制等待,直到X运行提交为止。当然,如果你想控制的更为精细,即订票员X在订前排位置,而订票员Y在订后排位置时,订票员Y能同时处理订票,可以使用如下语句:

    select chaired from seat where booked is null and location=’front’ for update

        一个良好的算法或许是订票员X订中心线左边的座位,Y订中心线右边的座位,以这种方式行事,只有在座位快满员时才可能发生阻塞。
        好了,来看看,数据库不一致的第二种情况(Non-repeatable Read),不可重复读包括三种情况:分别对应着DML的Insert,Delete,Update三种操作,其中前两种,在有些书籍上又称之为幻影读(Phantom read),为了演示这个特效,需要对MySQL的默认设置进行修改(set transaction isolation level read committed),为了节省时间,我在这就不贴效果图了。如果我们使用Oracle或者是MS SQL Server的话,在不修改任何配置的情况下,就可以看到效果。原因在于其默认的事务隔离级别是read committed。
        同理,要想看到脏读,也需要进行设置(set transaction isolation level read uncommitted),如下图所示:



        首先,订票员Z发现chairId的座位没有别人预定,于是她发出如下语句:

           这时,订票员X开始发出如下语句,

             这时,订票员Z回滚操作,原因是有人退票了。那么订票员X读到的数据就属于脏数据(因为booked列还是Z,与实际不符)。

            下面使用乐观锁进行一些实验:



         在这里,引入新的一列(这里是updateid),作为版本控制。现在我们来看看如何现实生活中的例子吧。比方说订票员X要求保留两个座位,订票员则要求三个座位。为了确保三个座位可用,我们可以使用如下方式:



          这个结果表明,三个在一起的座位,可以从座位号为1订起,分别为1,2,3。或者是从4开始订起(记住我们一共有6个座位),即4,5,6。
          好了,在订票员X和Y的两次订票过程中,updateid作为版本控制字段被返回,并且在任何后继的select和update操作中使用。这样,如果订票员X需要预订两个座位,那么她将做出如下操作:

        如上所示,订票员X操作后2 rows affected,这是正确的座位个数。因此,通过提交完成该事务。如果订票员Y此刻(注意:前一时刻 – 也就是在x还未提交更新数据前,Y也开启了一个事务,并发现连续的三个位置可以从1开始),准备预订3个座位,那么他的操作将如上图上所示,他应该能更新三条数据,但是受影响的只有一条,此刻,回滚事务,并且重新启动一个事务处理过程。如下图所示:

       如此,我们执行预订三个座位的操作,如下:

        至此,乐观锁的实战我们也看完了。在实际应用中,可以通过有效地算法,划分不同区域,使得搜索从不同空间开始,这样可以避免上述并发带来的一系列问题。


备注:
(1) Oracle中关闭自动提交功能的命令如下:set autocommit off。
(2) MySQL中,MyISAM数据库引擎不支持事务,所以我们可以在create table语句中指定engine=InnoDB来确保在指定表上应用事务。在MySQL中,我们可以这样开始一个事务:start transaction;
(3) 在PostgreSQL中,autocommit也称作链接模式(Chained Model),这是默认模式,需要使用begin trasaction开启事务。
(4) MS SQL Server也使用与PostgreSQL相同的语句开启事务。

(5) 幻读(Phantom Read):当两个一致的查询在一个事务内执行,第二个查询返回的行集不同于第一个查询返回的行集时,就发生了幻读。(主要与delete和insert操作有关)。
(6) 不可重复读(Nonrepeatable Read):当一个事务中的一个查询从数据库读取数据,但随后同一个事务的第二个操作欲查询相同数据时,却发现数据被另一个已经提交的事务修改,就发生了不可重复读。(和update操作有关)。
(7) 脏读(Dirty Read):除了可能读到第二个事务中未提交的数据外,脏读几乎与不可重复读完全一样。
(8) 如何查询当前数据库事务隔离级别:mysql中我们需要使用下面的语句:select @@tx_isolation。postgresql中则需要输入:show transaction isolation level。ms sql server中则需要输入:set transaction isolation level serializable。Oracle 中则需要使用v$session和v$transaction的组合得到隔离级别。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
6月前
|
SQL 关系型数据库 数据库
事务隔离级别:保障数据库并发事务的一致性与性能
事务隔离级别:保障数据库并发事务的一致性与性能
|
7天前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
20 2
|
16天前
|
存储 监控 关系型数据库
MySQL并发控制与管理:优化数据库性能的关键
【10月更文挑战第17天】MySQL并发控制与管理:优化数据库性能的关键
71 0
|
6月前
|
存储 安全 算法
【软件设计师备考 专题 】数据库的控制功能(并发控制、恢复、安全性、完整性)
【软件设计师备考 专题 】数据库的控制功能(并发控制、恢复、安全性、完整性)
119 0
|
4月前
|
存储 关系型数据库 MySQL
数据库并发问题17
【7月更文挑战第17天】数据库并发问题
40 3
|
6月前
|
SQL 关系型数据库 MySQL
关系型数据库的并发处理能力限制
【5月更文挑战第3天】关系型数据库的并发处理能力限制
84 8
关系型数据库的并发处理能力限制
|
4月前
|
分布式计算 数据库
现代数据库系统的并发控制与事务管理
数据库系统的并发控制与事务管理是保障数据一致性和并发访问效率的核心技术。本文深入探讨了现代数据库系统中常见的并发控制方法和事务管理机制,包括乐观并发控制和悲观并发控制,以及ACID特性的实现和应用。通过对比分析不同方法的优缺点,展示了在不同应用场景下如何选择合适的并发控制策略和事务管理方式,以达到最优的数据库性能和数据一致性。
|
4月前
|
SQL 存储 数据库
MSSQL数据库性能调优实战:索引、查询与并发控制的深度剖析
在数据库管理领域,Microsoft SQL Server(MSSQL)的性能调优是保障业务高效运行的核心任务
|
5月前
|
SQL 安全 关系型数据库
MySQL数据库——事务-简介、事务操作、四大特性、并发事务问题、事务隔离级别
MySQL数据库——事务-简介、事务操作、四大特性、并发事务问题、事务隔离级别
82 1
|
5月前
|
SQL NoSQL 关系型数据库
常用数据库的最大并发和实际并发
常用数据库的最大并发和实际并发
749 0