CN116561137A - 事务处理方法、装置、计算机设备及存储介质 - Google Patents

事务处理方法、装置、计算机设备及存储介质 Download PDF

Info

Publication number
CN116561137A
CN116561137A CN202210106276.2A CN202210106276A CN116561137A CN 116561137 A CN116561137 A CN 116561137A CN 202210106276 A CN202210106276 A CN 202210106276A CN 116561137 A CN116561137 A CN 116561137A
Authority
CN
China
Prior art keywords
transaction
lock
read
write
data record
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Pending
Application number
CN202210106276.2A
Other languages
English (en)
Inventor
王冬慧
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Tencent Technology Shenzhen Co Ltd
Original Assignee
Tencent Technology Shenzhen Co Ltd
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Tencent Technology Shenzhen Co Ltd filed Critical Tencent Technology Shenzhen Co Ltd
Priority to CN202210106276.2A priority Critical patent/CN116561137A/zh
Publication of CN116561137A publication Critical patent/CN116561137A/zh
Pending legal-status Critical Current

Links

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F16/00Information retrieval; Database structures therefor; File system structures therefor
    • G06F16/20Information retrieval; Database structures therefor; File system structures therefor of structured data, e.g. relational data
    • G06F16/23Updating
    • G06F16/2308Concurrency control
    • G06F16/2336Pessimistic concurrency control approaches, e.g. locking or multiple versions without time stamps
    • G06F16/2343Locking methods, e.g. distributed locking or locking implementation details
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F16/00Information retrieval; Database structures therefor; File system structures therefor
    • G06F16/20Information retrieval; Database structures therefor; File system structures therefor of structured data, e.g. relational data
    • G06F16/27Replication, distribution or synchronisation of data between databases or within a distributed database system; Distributed database system architectures therefor
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F16/00Information retrieval; Database structures therefor; File system structures therefor
    • G06F16/20Information retrieval; Database structures therefor; File system structures therefor of structured data, e.g. relational data
    • G06F16/28Databases characterised by their database models, e.g. relational or object models
    • G06F16/284Relational databases
    • YGENERAL TAGGING OF NEW TECHNOLOGICAL DEVELOPMENTS; GENERAL TAGGING OF CROSS-SECTIONAL TECHNOLOGIES SPANNING OVER SEVERAL SECTIONS OF THE IPC; TECHNICAL SUBJECTS COVERED BY FORMER USPC CROSS-REFERENCE ART COLLECTIONS [XRACs] AND DIGESTS
    • Y02TECHNOLOGIES OR APPLICATIONS FOR MITIGATION OR ADAPTATION AGAINST CLIMATE CHANGE
    • Y02DCLIMATE CHANGE MITIGATION TECHNOLOGIES IN INFORMATION AND COMMUNICATION TECHNOLOGIES [ICT], I.E. INFORMATION AND COMMUNICATION TECHNOLOGIES AIMING AT THE REDUCTION OF THEIR OWN ENERGY USE
    • Y02D10/00Energy efficient computing, e.g. low power processors, power management or thermal management

Landscapes

  • Engineering & Computer Science (AREA)
  • Databases & Information Systems (AREA)
  • Theoretical Computer Science (AREA)
  • Data Mining & Analysis (AREA)
  • Physics & Mathematics (AREA)
  • General Engineering & Computer Science (AREA)
  • General Physics & Mathematics (AREA)
  • Computing Systems (AREA)
  • Information Retrieval, Db Structures And Fs Structures Therefor (AREA)

Abstract

本申请公开了一种事务处理方法、装置、计算机设备及存储介质,属于数据库技术领域。该方法包括:基于目标事务所操作的数据记录,确定修改该数据记录的最新事务;基于全局读锁信息和该最新事务的写锁等待信息,对该目标事务进行锁申请的冲突检测;在该冲突检测指示存在冲突的情况下,申请对该数据记录添加与该操作的操作类型对应的锁。本申请通过事务锁方案实现并发控制,无需依赖于全局的锁管理器,仅针对存在冲突的情况才申请创建锁信息,针对不存在冲突的情况则无需耗费资源来维护锁信息,能够极大减少系统内创建不必要的行锁,从而节约锁机制下并发控制的存储开销和内存占用。

Description

事务处理方法、装置、计算机设备及存储介质
技术领域
本申请涉及数据库技术领域,特别涉及一种事务处理方法、装置、计算机设备及存储介质。
背景技术
随着数据库技术的发展,MySQL是目前最流行的开源关系型数据库管理系统之一,MySQL数据库系统默认的存储引擎为InnoDB引擎,InnoDB引擎通过表锁(Table Lock)和行锁(Record Lock)的机制来实现数据库事务的并发控制。
在InnoDB引擎中会维护一个全局的锁管理器(Lock System),锁管理器是一个用于管理各事务对应表锁和行锁的全局数据结构,在高并发场景下,基于封锁的并发控制机制,需要对每个并发事务在锁管理器中申请锁资源,如果这些并发事务之间本身冲突较小,会导致创建很多不必要的行锁,这些不必要的行锁对于内存占用较多,存储开销很大。
发明内容
本申请实施例提供了一种事务处理方法、装置、计算机设备及存储介质,能够节约实现锁机制下对系统的内存占用和存储开销。该技术方案如下:
一方面,提供了一种事务处理方法,所述方法包括:
基于目标事务所操作的数据记录,确定修改所述数据记录的最新事务;
基于全局读锁信息和所述最新事务的写锁等待信息,对所述目标事务进行锁申请的冲突检测,所述全局读锁信息用于管理数据库系统中的读锁,所述写锁等待信息用于记录等待所述最新事务所持有写锁的各个事务;
在所述冲突检测指示存在冲突的情况下,申请对所述数据记录添加与所述操作的操作类型对应的锁。
一方面,提供了一种事务处理装置,所述装置包括:
确定模块,用于基于目标事务所操作的数据记录,确定修改所述数据记录的最新事务;
冲突检测模块,用于基于全局读锁信息和所述最新事务的写锁等待信息,对所述目标事务进行锁申请的冲突检测,所述全局读锁信息用于管理数据库系统中的读锁,所述写锁等待信息用于记录等待所述最新事务所持有写锁的各个事务;
锁申请模块,用于在所述冲突检测指示存在冲突的情况下,申请对所述数据记录添加与所述操作的操作类型对应的锁。
在一种可能实施方式中,所述冲突检测模块包括:
确定单元,用于基于所述操作类型,确定所述目标事务待申请的锁类型;
第一冲突检测单元,用于在所述锁类型为读锁的情况下,仅对所述目标事务进行写锁冲突检测;
第二冲突检测单元,用于在所述锁类型为写锁的情况下,对所述目标事务进行读锁冲突检测和写锁冲突检测。
在一种可能实施方式中,所述第一冲突检测单元包括:
获取子单元,用于在所述锁类型为读锁的情况下,获取所述最新事务的事务状态;
确定子单元,用于在所述事务状态不是活跃状态的情况下,将冲突检测结果确定为不存在冲突;
所述确定子单元,还用于在所述事务状态是活跃状态的情况下,将所述冲突检测结果确定为存在冲突。
在一种可能实施方式中,在所述事务状态不是活跃状态的情况下,所述第一冲突检测单元还包括:
查询子单元,用于在所述全局读锁信息中,以所述数据记录的记录标识为索引,查询所述数据记录的读锁持有队列,所述读锁持有队列用于记录持有所述数据记录的读锁的各个事务;
添加子单元,用于在所述读锁持有队列中不包含所述目标事务的情况下,将所述目标事务添加至所述读锁持有队列。
在一种可能实施方式中,所述最新事务的写锁等待信息包括所述最新事务所操作的每条数据记录的写锁等待队列,所述写锁等待队列用于记录等待所述最新事务对所述数据记录所持有写锁的各个事务;
在所述事务状态是活跃状态的情况下,所述第一冲突检测单元还包括:
添加子单元,用于在所述最新事务的写锁等待信息中,将所述目标事务添加至所述数据记录的写锁等待队列;
设置子单元,用于将所述目标事务的阻塞事务参数设置为所述最新事务的事务标识,所述阻塞事务参数用于表征所述目标事务所等待的事务。
在一种可能实施方式中,所述第二冲突检测单元包括:
读锁冲突检测子单元,用于在所述锁类型为写锁的情况下,对所述目标事务进行读锁冲突检测;
确定子单元,用于在所述读锁冲突检测指示存在读锁冲突的情况下,将冲突检测结果确定为存在冲突;
写锁冲突检测子单元,用于在所述读锁冲突检测指示不存在读锁冲突的情况下,对所述目标事务进行写锁冲突检测;
所述确定子单元,还用于若所述写锁冲突检测指示存在写锁冲突,则将所述冲突检测结果确定为存在冲突;若所述写锁冲突检测指示不存在写锁冲突,则将所述冲突检测结果确定为不存在冲突。
在一种可能实施方式中,所述读锁冲突检测子单元用于:
在所述全局读锁信息中,以所述数据记录的记录标识为索引,查询所述数据记录的读锁持有队列,所述读锁持有队列用于记录持有所述数据记录的读锁的各个事务;
在所述读锁持有队列为空的情况下,返回不存在读锁冲突;
在所述读锁持有队列仅包含所述目标事务的情况下,查询所述数据记录的读锁等待队列,所述读锁等待队列用于记录等待对所述数据记录所持有读锁的各个事务;在所述读锁等待队列为空的情况下,返回不存在读锁冲突;在所述读锁等待队列不为空的情况下,返回存在读锁冲突;
在所述读锁持有队列包含除了所述目标事务之外的事务的情况下,返回存在读锁冲突。
在一种可能实施方式中,在所述读锁持有队列仅包含所述目标事务且所述读锁等待队列不为空,或者,所述读锁持有队列包含除了所述目标事务之外的事务的情况下,所述第二冲突检测单元还包括:
添加子单元,用于将所述目标事务添加至所述读锁等待队列;
所述添加子单元,还用于基于所述目标事务的写锁等待信息,确定等待所述目标事务对所述数据记录所申请写锁的各个事务;将所述等待所述目标事务对所述数据记录所申请写锁的各个事务添加到所述读锁等待队列。
在一种可能实施方式中,所述第二冲突检测单元还包括:
设置子单元,用于对添加到所述读锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述读锁持有队列中除了所述事务之外的第一个事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
在一种可能实施方式中,所述写锁冲突检测子单元用于:
获取所述最新事务的事务状态;
在所述事务状态不是活跃状态的情况下,返回不存在写锁冲突;
在所述事务状态是活跃状态的情况下,返回存在写锁冲突。
在一种可能实施方式中,在所述事务状态不是活跃状态的情况下,所述第二冲突检测单元还包括:
写入子单元,用于在所述数据记录的目标隐藏字段中,写入所述目标事务的事务标识,其中,所述目标隐藏字段用于记录修改所述数据记录的最新事务的事务标识。
在一种可能实施方式中,所述最新事务的写锁等待信息包括所述最新事务所操作的每条数据记录的写锁等待队列,所述写锁等待队列用于记录等待所述最新事务对所述数据记录所持有写锁的各个事务;
在所述事务状态是活跃状态的情况下,所述第二冲突检测单元还包括:
添加子单元,用于在所述最新事务的写锁等待信息中,将所述目标事务添加至所述数据记录的写锁等待队列;
所述添加子单元,还用于基于所述目标事务的写锁等待信息,确定等待所述目标事务对所述数据记录所申请写锁的各个事务;在所述最新事务的写锁等待信息中,将所述等待所述目标事务对所述数据记录所申请写锁的各个事务添加到所述数据记录的写锁等待队列。
在一种可能实施方式中,所述第二冲突检测单元还包括:
设置子单元,用于对添加到所述写锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述最新事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
在一种可能实施方式中,在所述锁类型为读锁的情况下,所述冲突检测模块还包括:
查询单元,用于在所述目标事务提交后,在所述全局读锁信息中,以所述数据记录的记录标识为索引,查询所述数据记录的读锁持有队列,所述读锁持有队列用于记录持有所述数据记录的读锁的各个事务;
唤醒单元,用于在所述读锁持有队列为空的情况下,唤醒所述数据记录的读锁等待队列中的第一个事务,所述读锁等待队列用于记录等待对所述数据记录所持有读锁的各个事务;
所述唤醒单元,还用于在所述读锁持有队列仅包含单个事务,且所述事务恰好是所述读锁等待队列中的第一个事务的情况下,唤醒所述事务;
设置单元,用于否则,对所述读锁等待队列中的每个事务,将所述事务的阻塞事务参数设置为所述读锁持有队列中除了所述事务之外的第一个事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
在一种可能实施方式中,对于所述目标事务提交后唤醒的事务,所述冲突检测模块还包括:
添加单元,用于在所述唤醒的事务的写锁等待信息中,将所述读锁等待队列中除了所述唤醒的事务之外的各个事务添加至所述数据记录的写锁等待队列;
所述设置单元,还用于对添加到所述写锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述唤醒的事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
在一种可能实施方式中,在所述锁类型为写锁的情况下,所述冲突检测模块还包括:
遍历单元,用于在所述目标事务提交后,遍历所述目标事务的写锁等待信息中每条数据记录的写锁等待队列,所述写锁等待队列用于记录等待所述目标事务对所述数据记录所持有写锁的各个事务;
唤醒单元,用于对任一数据记录的写锁等待队列,在所述写锁等待队列的第一个事务申请的锁类型为写锁的情况下,唤醒所述第一个事务;在所述写锁等待队列的第一个事务申请的锁类型为读锁的情况下,唤醒所述写锁等待队列中申请的锁类型为读锁的所有事务。
在一种可能实施方式中,对任一数据记录的写锁等待队列,在所述写锁等待队列的第一个事务申请的锁类型为写锁的情况下,对于所述第一个事务,所述冲突检测模块还包括:
添加单元,用于在所述第一个事务的写锁等待信息中,将所述写锁等待队列中除了所述第一个事务之外的各个事务添加至所述数据记录的写锁等待队列;
所述设置单元,还用于对添加到所述写锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述第一个事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
在一种可能实施方式中,对任一数据记录的写锁等待队列,在所述写锁等待队列的第一个事务申请的锁类型为读锁的情况下,所述冲突检测模块还包括:
添加单元,用于在所述全局读锁信息中,将所述写锁等待队列中申请的锁类型为读锁的所有事务添加至所述数据记录的读锁持有队列;
所述添加单元,还用于将所述写锁等待队列中申请的锁类型为写锁的所有事务添加到所述数据记录的读锁等待队列。
在一种可能实施方式中,所述设置单元还用于:
对添加到所述读锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述读锁持有队列中除了所述事务之外的第一个事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
在一种可能实施方式中,所述确定模块还用于:在所述目标事务回滚后,基于所述目标事务的阻塞事务参数,确定所述目标事务所等待的第一事务;
所述装置还包括:
删除模块,用于在所述第一事务的写锁等待信息中,从所述目标事务所操作的数据记录的写锁等待队列中删除所述目标事务;
所述删除模块,还用于在所述全局读锁信息中,从所述目标事务所操作的数据记录的读锁等待队列中删除所述目标事务。
在一种可能实施方式中,所述装置还包括:
查询模块,用于在所述全局读锁信息中,以所述数据记录的记录标识为索引,查询所述数据记录的读锁持有队列,所述读锁持有队列用于记录持有所述数据记录的读锁的各个事务;
唤醒模块,用于在所述读锁持有队列仅包含单个事务,且所述事务恰好是所述读锁等待队列中的第一个事务的情况下,唤醒所述事务。
一方面,提供了一种计算机设备,该计算机设备包括一个或多个处理器和一个或多个存储器,该一个或多个存储器中存储有至少一条计算机程序,该至少一条计算机程序由该一个或多个处理器加载并执行以实现如上述的事务处理方法。
一方面,提供了一种存储介质,该存储介质中存储有至少一条计算机程序,该至少一条计算机程序由处理器加载并执行以实现如上述的事务处理方法。
一方面,提供一种计算机程序产品或计算机程序,所述计算机程序产品或所述计算机程序包括一条或多条程序代码,所述一条或多条程序代码存储在计算机可读存储介质中。计算机设备的一个或多个处理器能够从计算机可读存储介质中读取所述一条或多条程序代码,所述一个或多个处理器执行所述一条或多条程序代码,使得计算机设备能够执行上述的事务处理方法。
本申请实施例提供的技术方案带来的有益效果至少包括:
通过全局读锁信息记录数据库系统中的读锁的相关信息,通过修改每条数据记录的最新事务能够确定在该数据记录上是否存在写锁以及写锁的锁持有者,并且将写锁等待信息打散存储到每个事务的上下文信息中,使得整个数据库系统的读写冲突检测无需依赖于锁管理器,也无需每次访问互斥量,利用全局读锁信息和所欲操作的数据记录所对应最新事务的写锁等待信息完成冲突检测后,能够仅针对存在冲突的情况,才申请创建相应的锁信息,针对不存在冲突的情况则无需耗费资源来维护锁信息,能够极大减少系统内创建不必要的行锁,从而节约锁机制下并发控制的存储开销和内存占用。
附图说明
为了更清楚地说明本申请实施例中的技术方案,下面将对实施例描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本申请的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还能够根据这些附图获得其他的附图。
图1是本申请实施例提供的一种事务处理方法的实施环境示意图;
图2是本申请实施例提供的一种写锁等待信息的逻辑示意图;
图3是本申请实施例提供的一种全局读锁信息的逻辑示意图;
图4是本申请实施例提供的一种事务处理方法的流程图;
图5是本申请实施例提供的一种事务处理方法的流程图;
图6是本申请实施例提供的一种事务处理方法的流程图;
图7是本申请实施例提供的一种事务处理装置的结构示意图;
图8是本申请实施例提供的一种计算机设备的结构示意图;
图9是本申请实施例提供的一种计算机设备的结构示意图。
具体实施方式
为使本申请的目的、技术方案和优点更加清楚,下面将结合附图对本申请实施方式作进一步地详细描述。
本申请中术语“第一”“第二”等字样用于对作用和功能基本相同的相同项或相似项进行区分,应理解,“第一”、“第二”、“第n”之间不具有逻辑或时序上的依赖关系,也不对数量和执行顺序进行限定。
本申请中术语“至少一个”是指一个或多个,“多个”的含义是指两个或两个以上,例如,多个第一位置是指两个或两个以上的第一位置。
本申请中术语“包括A或B中至少一项”涉及如下几种情况:仅包括A,仅包括B,以及包括A和B两者。
本申请中涉及到的用户相关的数据,当以本申请实施例的方法运用到具体产品或技术中时,都需要获取用户许可或者同意或者充分授权,且相关数据的收集、使用和处理需要遵守所在国家相关法律法规和国家标准。
在介绍本申请实施例之前,需要引入一些云技术领域内的基本概念。
云技术(Cloud Technology):是指在广域网或局域网内将硬件、软件、网络等系列资源统一起来,实现数据的计算、储存、处理和共享的一种托管技术,也即是基于云计算商业模式应用的网络技术、信息技术、整合技术、管理平台技术、应用技术等的总称,可以组成资源池,按需所用,灵活便利。云计算技术将变成云技术领域的重要支撑。技术网络系统的后台服务需要大量的计算、存储资源,如视频网站、图片类网站和更多的门户网站。伴随着互联网行业的高度发展和应用,将来每个物品都有可能存在自己的识别标志,都需要传输到后台系统进行逻辑处理,不同程度级别的数据将会分开处理,各类行业数据皆需要强大的系统后盾支撑,均能通过云计算来实现。
云存储(Cloud Storage):是在云计算概念上延伸和发展出来的一个新的概念,分布式云存储系统(以下简称存储系统)是指通过集群应用、网格技术以及分布存储文件系统等功能,将网络中大量各种不同类型的存储设备(存储设备也称之为存储节点)通过应用软件或应用接口集合起来协同工作,共同对外提供数据存储和业务访问功能的一个存储系统。
数据库(Database):简而言之可视为一种电子化的文件柜——存储电子文件的处所,用户可以对文件中的数据进行新增、查询、更新、删除等操作。所谓“数据库”是以一定方式储存在一起、能与多个用户共享、具有尽可能小的冗余度、与应用程序彼此独立的数据集合。
以下,对本申请实施例所涉及的术语进行解释说明。
MySQL数据库:MySQL是目前最流行的开源关系型数据库管理系统之一。由瑞典MySQL AB公司开发,属于Oracle(甲骨文)旗下产品。其中,SQL的英文全称为StructuredQuery Language,中文全称为结构化查询语言。
InnoDB引擎:是MySQL数据库系统的数据库引擎之一,现为MySQL数据库系统的默认存储引擎。InnoDB引擎通过表锁(Table Lock)和行锁(Record Lock)的机制来实现数据库事务的并发控制。
B+tree:即B+树,是一种多叉树的数据结构,InnoDB引擎的表数据文件由多个B+tree组成,其中,一个数据页(Page)对应B+tree的一个节点,InnoDB引擎中数据页的默认大小是16KB。另外,B+tree在非叶子节点上是不存储数据的,仅存储键值,而在叶子节点中不仅存储键值,也会存储数据。
锁机制:在数据库系统中,会存在同时有不同的事务需要修改同一条数据记录的现象,通过锁机制来保证这些数据记录在不同并发的事务中的修改正确性,换言之,锁机制能够保证在多并发事务环境中,在某一个时间点上,只能有一个事务能够获得某一条数据记录的锁,从而保证数据记录的一致性。
锁管理器(Lock System):锁管理器是InnoDB引擎中一个用于管理各事务对应表锁和行锁的全局数据结构。锁管理器的关键成员变量是一个哈希表,哈希表的键(Key,也称键名)为数据表或者记录行的唯一标识,哈希表的值(Value)为一个表锁(Table Lock)或者行锁(Record Lock),其中,在数据表中每一行对应于一条数据记录,因此数据表中的每一行也称为记录行。在InnoDB引擎中,通过互斥量(Mutex)控制并发事务对全局锁管理器的访问和修改的正确性。
数据记录(Record):通常是指关系型数据库中的数据表中的某一行数据记录,这个数据记录存储了数据表的定义中所有数据列的实例化信息(即每个数据列对应的字段数据),并按照数据列定义的顺序排列,组成一个连续的内容,也即是说,这段连续的内容被称为数据表的一条数据记录,也称为元组(Tuple)。
事务(Transaction):事务是数据库管理系统在执行操作的过程中的一个逻辑单位,由一个有限的数据库操作序列构成,是数据库系统操作的最小执行单位。在一个系统的内部,每个操作系列的单位,称为一个事务,单个操作也可以称为一个事务。
操作:一个数据库操作由操作类型、事务、变量版本三部分构成,即是指事务对哪个版本的变量执行何种类型的数据库操作,其中,操作类型包括读(Read)和写(Write)两种,而变量是数据库操作的作用者(或者说操作对象),一个变量可以包含若干变量版本(也称为版本),每当事务对变量进行更新时,则会添加新的变量版本,变量的各个变量版本通常以自然数作为版本号标识,版本号越大,则表示变量版本越新。
读锁:即共享锁(Shared Lock,S锁),若事务T对数据对象A加上读锁,则事务T可以读A但不能修改A,其他事务只能再对A加读锁,而不能加写锁,直到事务T释放A上的读锁。这保证了其他事务可以读A,但在事务T释放A上的读锁之前不能对A做任何修改。
写锁:即排他锁(eXclusive Lock,X锁),若事务T对数据对象A加上写锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到事务T释放A上的写锁。这保证了其他事务在事务T释放A上的写锁之前不能再读取和修改A。
在MySQL数据库系统的InnoDB引擎中,通常使用表锁和行锁来进行事务的并发控制,而全局的锁管理器则用于维护所有并发事务的锁信息。目前的基于封锁的并发控制机制,每个事务在尝试获取数据记录上的锁时,即事务向锁管理器申请对该数据记录加锁时,会首先访问锁管理器的互斥量(即内存中开辟的一个临界区),与互斥量中已有的锁项进行冲突检测,即,基于该事务所操作(读操作或写操作)的数据记录的记录标识(Identification,ID),在该互斥量中查询该记录ID是否存在冲突的已有锁项,如果没有检测到冲突,则在锁管理器中插入一条新的对该数据记录的行锁,代表该事务持有该数据记录的锁,比如,将该行锁添加到哈希表的头部,并对该事务返回加锁成功;如果检测到冲突,同样也会对创建一条对该数据记录的行锁,但是将创建的行锁添加到哈希表的尾部,并对该事务返回锁等待,由于哈希表可视为具有先进先出属性的一个队列,当插入行锁到哈希表头部时,相当于加锁成功,该事务已经申请到并持有了数据记录上的锁,当插入行锁到哈希表尾部时,需要等待哈希表中之前所有的行锁对应事务提交或者回滚并释放在该数据记录上的锁资源之后,该事务才能持有在该数据记录上的锁。此外,当持有对某条数据记录的行锁的事务提交时,该事务会先在锁管理器中记载了该行锁的哈希表中删除该行锁,然后遍历锁管理器中具有相同Key(即记录ID)的锁项,并判断是否能够唤醒在该数据记录上的下一个事务,从而实现已提交事务释放在数据记录上申请到的锁资源。
能够看出来,由于每个事务在尝试申请一个锁时,都需要访问锁管理器的互斥量,这对于高并发场景下的事务处理来说,成为一个十分影响数据库系统并发度的瓶颈。在并发事务之间冲突较小的情况下,由于每个并发事务都需要在锁管理器中申请锁资源,会导致创建很多不必要的行锁,这是因为冲突较小时这些锁在其生命周期(即锁的存续期间)内大概率是不会被用来判断冲突的,而这些不必要的行锁对于内存占用较多,存储开销很大,并且如果某个并发事务修改的数据量较为庞大时,需要对该并发事务修改的每一条数据记录都申请锁资源,导致全局的锁管理器占用的内存量急剧增长。此外,为了保证全局的锁管理器的多线程安全性,并发事务在修改锁管理器中的元素时需要对其加上互斥量,在冲突较高时,互斥量保护的关键代码区会变长,导致争用也随之变高,从而引发系统性能的急剧下降。
有鉴于此,本申请实施例提供一种事务处理方法,涉及到基于事务锁的数据库事务并发控制方案(后文中均简称为“事务锁方案”),由于事务锁方案不依赖于全局的锁管理器来管理数据库系统内的锁信息,能够解决原生的InnoDB引擎中全局锁管理器在高并发场景下存在的内存增长和性能下降的问题,此外,由于将写锁等待信息分散保存在对应事务的上下文信息中,能够解决全局的互斥量争用带来的性能影响。并且,在事务锁方案中,只有在冲突真正发生时才会创建事务等待信息,在检测到事务不存在冲突时,需要创建的相关信息很少,因此锁管理需要消耗的内存大小显著降低。
进一步的,在事务锁方案中,通过InnoDB引擎中每条数据记录上的事务号所在的隐藏字段(TRX_ID字段),能够确定出修改该数据记录的最新事务,通过判断当前事务与其操作的数据记录上记载的最新事务之间是否存在冲突,如果存在冲突,则将等待信息记录到最新事务的上下文信息中,即将当前事务挂载到最新事务的写锁等待信息中,如果不存在冲突那么无需进行任何操作,直接执行事务并提交或回滚即可,而无需在数据库系统中申请任何锁资源。由于事务锁方案抛弃了使用集中式的数据结构(即锁管理器)来管理锁信息,因此简化了锁逻辑和创建的锁个数,从而降低了原生锁管理器在事务冲突较高时维护锁信息的存储开销。
上述事务锁方案可适用于任一数据库系统,如单机数据库系统、集群数据库系统均能够实现事务锁方案,其中,集群数据库系统包括中央集群数据库和分布式集群数据库,而分布式集群数据库包括分布式数据库系统、分布式大数据处理系统以及采用类似架构的分布式数据库管理系统等。
在数据库系统中包括多个计算设备即计算节点,每个计算设备的数据库中存储有一个或多个数据表,每个数据表用于存储一个或多个数据行(数据记录),其中,每一个数据行由一组按照相同位置索引排列的字段集组成。其中,计算设备的数据库为关系型数据库或者非关系型数据库,例如SQL数据库、MySQL、NoSQL、NewSQL(泛指各种新式的可拓展/高性能数据库)等,在本申请实施例中对数据库的类型不作具体限定。
在一些实施例中,上述事务锁方案还能够应用于一种基于区块链技术的数据库系统(以下简称为“区块链系统”),上述区块链系统在本质上属于一种去中心化式的分布式数据库系统,采用共识算法保持区块链上不同计算设备所记载的账本数据一致,通过密码算法保证不同计算设备之间账本数据的加密传送以及不可篡改,通过脚本系统来拓展账本功能,通过网络路由来进行不同计算设备之间的相互连接。
在区块链系统中可以包括一条或多条区块链,区块链是一串使用密码学方法相关联产生的数据块,每一个数据块中包含了一批次网络交易的信息,用于验证其信息的有效性(防伪)和生成下一个区块。
区块链系统中计算设备之间可以组成点对点(Peer To Peer,P2P)网络,P2P协议是一个运行在传输控制协议(Transmission Control Protocol,TCP)协议之上的应用层协议。在区块链系统中,任一计算设备可以具备如下功能:1)路由,计算设备具有的基本功能,用于支持计算设备之间的通信;2)应用,用于部署在区块链中,根据实际业务需求而实现特定业务,记录实现功能相关的数据形成账本数据,在账本数据中携带数字签名以表示数据来源,将账本数据发送至区块链系统中的其他计算设备,供其他计算设备在验证账本数据来源以及完整性成功时,将账本数据添加至临时区块中,其中,应用实现的业务可以包括钱包、共享账本、智能合约等;3)区块链,包括一系列按照先后的时间顺序相互接续的区块,新区块一旦加入到区块链中就不会再被移除,区块中记录了区块链系统中计算设备提交的账本数据。
在一些实施例中,每个区块中可以包括本区块存储交易记录的哈希值(本区块的哈希值)以及前一区块的哈希值,各区块通过哈希值连接形成区块链,另,区块中还可以包括有区块生成时的时间戳等信息。
以下,对本申请实施例的系统架构进行说明。
图1是本申请实施例提供的一种事务处理方法的实施环境示意图。参见图1,以分布式集群数据库系统为例进行说明,分布式集群数据库系统包括:应用客户端101、网关服务器102以及分布式存储集群103。
应用客户端101是指用户侧的终端上安装和运行的能够发起数据请求的客户端,该数据请求可以是DDL(Data Definition Language,数据定义语言)请求或者DML(DataManipulate Language,数据操纵语言)请求等,本申请实施例对此不进行具体限定。可选地,应用客户端101的类型包括但不限于:支付应用、社交应用、音视频应用、直播应用、购物应用、外卖应用或者打车应用等,本申请实施例不对应用客户端101的类型进行具体限定。在一些实施例中,用户侧的终端也称为用户设备、终端设备、用户终端、移动终端、智能终端、通信设备等。可选地,终端的设备类型包括:智能手机、平板电脑、笔记本电脑、台式计算机、智能音箱、智能手表、车载终端、智能家电、智能语音交互设备等,但并不局限于此。
应用客户端101以及网关服务器102能够通过有线或无线通信方式进行直接或间接地连接,本申请在此不做限制。
网关服务器102用于接收外部的数据请求,并将数据请求对应的读写事务分发至分布式存储集群103,示意性地,用户在终端上登录应用客户端101,触发应用客户端101生成数据请求,接着,调用分布式集群数据库系统提供的API(Application ProgrammingInterface,应用程序编程接口)将该数据请求发送至网关服务器102,比如,该API可以是MySQL API(一种关系型数据库系统提供的API)。例如,在智慧交通场景下,该数据请求可以是用于新增停车位的请求,或者是用于查询已有停车位的请求等。
在一些实施例中,该网关服务器102可以与分布式存储集群103中的任一个计算设备合并在同一个物理机上,也即是,让某个计算设备充当网关服务器102。
分布式存储集群103包括一个或多个计算设备,例如,计算设备的数量为m个,m为大于或等于1的整数,本申请实施例不对分布式存储集群103中计算设备的数量进行具体限定。可选地,每个计算设备采用主备结构(也即是为一主多备集群),如图1所示,以计算设备为一主两备集群为例进行示意,每个计算设备中包括一个主机和两个备机,可选地,每个主机或备机都对应配置有代理(Agent)设备,代理设备可以与主机或备机是物理独立的,当然,代理设备还可以作为主机或备机上的一个代理模块,以计算设备1为例,计算设备1包括一个主数据库及代理设备(主database+agent,简称主DB+agent),此外还包括两备数据库及代理设备(备database+agent,简称备DB+agent)。
在一个示例性场景中,每个计算设备所对应的主机或备机的数据库实例集合称为一个SET(集合),例如,假设某一计算设备为单机设备,那么该计算设备的SET仅为该单机设备的数据库实例,假设某一计算设备为一主两备集群,那么该计算设备的SET为主机数据库实例以及两个备机数据库实例的集合。
在一些实施例中,上述网关服务器102以及分布式存储集群103所构成的分布式集群数据库系统,可以视为一种向用户终端提供数据服务的服务器,该服务器可以是独立的物理服务器,也可以是多个物理服务器构成的服务器集群或者分布式系统,还可以是提供云服务、云数据库、云计算、云函数、云存储、网络服务、云通信、中间件服务、域名服务、安全服务、CDN(Content Delivery Network,内容分发网络)、以及大数据和人工智能平台等基础云计算服务的云服务器。
以下,将基于上述实施环境,对本申请实施例涉及的事务锁方案中锁信息的表示存储方式进行介绍,事务锁方案不依赖于全局的锁管理器,对于读锁信息,使用一张全局的哈希表(Hash Table)来进行保存,对于写锁信息,则复用每条数据记录上事务号所在的隐藏字段(DB_TRX_ID)字段来表示写锁信息,并且在每个事务的上下文信息中新增一个哈希表来表示写锁等待信息(即正在等待本事务所持有写锁的各个事务的相关信息),相当于将写锁等待信息分散到每个事务的上下文信息中进行维护,能够进一步节约存储开销。下面分别介绍读锁信息和写锁信息是如何表示与存储的。
在InnoDB引擎中,每条数据记录中除了自身的各个字段值之外,在数据记录的开头还会包含两个隐藏字段,其中1个是事务号(DB_TRX_ID)字段,另外一个是回滚指针(DB_ROLL_PTR)字段,每条数据记录的存储结构如下表1所示:
表1
DB_TRX_ID DB_ROLL_PTR C1 C2
其中,事务号(DB_TRX_ID)字段上记录了正在修改或者修改了本数据记录的最新事务的事务标识(即事务ID),根据这条事务ID能够从内存中的活跃事务列表中访问到该最新事务的事务状态,通过该事务状态能够判断该最新事务是否持有该数据记录上的写锁,例如,事务状态为活跃状态(Active)时,代表最新事务持有该数据记录上的写锁,后面新来的事务均需要等待正在修改该数据记录的最新事务释放了写锁之后,才能够对该数据记录进行读写操作。
其中,回滚指针(DB_ROLL_PTR)字段上记录了该数据记录的Undo Log(回滚日志)的指针,以便于在进行事务回滚时,通过回滚日志将该数据记录恢复到上一版本。
其中,C1和C2字段以及后续其他字段都是该数据记录原本要存储的字段值,即,C1字段用于存储该数据记录在数据列C1上的字段值,C2字段用于存储该数据记录在数据列C2上的字段值,以此类推,后面不做赘述。
在事务锁方案中,由于InnoDB引擎在每条数据记录上事务号(DB_TRX_ID)字段都能够指示修改该数据记录的最新事务,最新事务的活跃状态又能够反映出该数据记录是否被添加了写锁(如果被添加了写锁,当然也能确定出锁持有者就是该最新事务),因此事务号(DB_TRX_ID)字段能够充分反映出每条数据记录的写锁信息。
进一步的,由于每个事务在创建时,都会在内存中初始化本事务的上下文信息,事务锁方案中,通过在每个事务的上下文信息中新增一个哈希表字段(TRX_LOCK_WAIT)来表示本事务的写锁等待信息,该哈希表中会对本事务所操作的所有数据记录均创建一个Key-Value数据结构,对每条数据记录的Key-Value数据结构来说,Key(键名)为该数据记录的唯一记录标识(即记录ID),Value(键值)则为等待本事务对该数据记录所持有写锁的各个事务,因此Value也称为该数据记录的写锁等待队列,写锁等待队列中包含一系列等待本事务对该数据记录所持有写锁的事务的事务ID。
图2是本申请实施例提供的一种写锁等待信息的逻辑示意图,如图2所示,示出了某一事务在其上下文信息中开辟的写锁等待信息200(即一张哈希表),哈希表中对该事务所操作的每条数据记录都创建一个Key-Value数据结构210,Key中存储数据记录的记录ID,Value中存储数据记录的写锁等待队列。在一个示例中,key1中存储该事务所操作的第1条数据记录的记录ID,key1对应Value上挂载在等待该事务对该第1条数据记录所持有写锁的各个事务的事务ID所形成的写锁等待队列(记作wait_que_write)。
此外,针对读锁信息,维护一张全局的哈希表(slock_table),该全局的哈希表也称为全局读锁信息,全局读锁信息用于管理数据库系统中的读锁。可选地,全局读锁信息slock_table中对整个数据库系统中正在被读取的每条数据记录也创建一个Key-Value数据结构,对每条数据记录的Key-Value数据结构来说,Key(键名)为该数据记录的唯一记录标识(即记录ID),Value(键值)中则包含一个队列对(即包含两个队列),其中一个是读锁持有队列(hold_que_read),读锁持有队列用于记录持有该数据记录的读锁的各个事务的事务ID,另外一个是读锁等待队列(wait_que_read),读锁等待队列用于记录等待对该数据记录所持有读锁的各个事务的事务ID。
图3是本申请实施例提供的一种全局读锁信息的逻辑示意图,如图3所示,示出了一种全局读锁信息300,全局读锁信息300是一张全局的哈希表,哈希表中对正在被读取的每条数据记录都创建一个Key-Value数据结构310,Key中存储数据记录的记录ID,Value中存储数据记录的读锁持有队列(hold_que_read)和读锁等待队列(wait_que_read)。在一个示例中,key1中存储目前系统中正在被读取的某条数据记录的记录ID,key1对应的Value上挂载了两个队列,一个是持有该数据记录的读锁的各个事务的事务ID所形成的读锁持有队列(hold_que_read),另一个是等待对该数据记录所持有读锁的各个事务的事务ID所形成的读锁等待队列(wait_que_read)。
在上述基础上,由于数据库系统内维护了一个全局读锁信息,用于记录读锁相关信息,而针对每个事务在其上下文信息中开辟哈希表字段来表征写锁等待信息,因此整体对系统内的读锁信息、写锁信息均能够进行整体维护,且无需依赖于全局的锁管理器。
在一些实施例中,与全局读锁信息类似,也可以使用一个全局的数据结构来存储写锁等待信息,并对全局的写锁等待信息进行分区,在加锁时仍然以数据记录上的事务号(DB_TRX_ID)字段来判断冲突,冲突后则将需要等待的事务添加到全局的数据结构中,并以分区为粒度添加互斥量,在事务提交和事务回滚时同样需要获得对应分区的互斥量,在后续的各个实施例中,均以将写锁等待信息分散存储到每个事务的上下文信息中为例进行说明。
在介绍了上述事务锁方案中锁信息的表示和存储机制的基础上,本申请实施例将对事务锁方案下整体的事务处理流程进行简单说明,图4是本申请实施例提供的一种事务处理方法的流程图。参见图4,该实施例由电子设备执行,该电子设备可以是数据库系统中的计算设备(即计算设备,SQL引擎)或者存储设备(即存储节点,即存储引擎),这里以电子设备为计算设备为例进行说明,该实施例包括下述步骤:
401、计算设备基于目标事务所操作的数据记录,确定修改该数据记录的最新事务。
其中,该目标事务基于数据请求解析得到,该数据请求包括DDL请求和DML请求,DML请求是指业务请求,例如查询请求是一种典型的业务请求,在金融场景下,该查询请求为查询余额、查询流水等,在智慧交通场景下,该查询请求为查询附近空闲停车位、查询目的地附近的路况等,本申请实施例不对数据请求的内容进行具体限定。
在一些实施例中,该数据请求是由用户通过应用客户端向数据库系统发送的,示意性地,用户在终端上登录应用客户端,触发应用客户端生成该数据请求,调用MySQL API将该数据请求发送至My SQL数据库系统,例如,My SQL数据库系统是仅包含该计算设备的单机数据库系统,或者,My SQL数据库系统是上述图1所示实施环境中的分布式数据库系统,而计算设备则是分布式存储集群中的一个计算节点,本申请实施例对此不进行具体限定。
在一些实施例中,计算设备接收到任一报文后,解析该报文的头字段,当该头字段指示该报文为数据请求时,解析该数据请求的数据字段,得到该数据请求所对应的目标事务的SQL语句(或者,该数据请求也可以是NoSQL请求,此时解析到的通常是针对某一Key-Value数据结构的访问)。
接着,基于该目标事务的SQL语句,确定该目标事务所操作的一条或多条数据记录,其中该目标事务对该数据记录的“操作”是指数据库操作,数据库操作的操作类型包括读操作和写操作,两者合并称为读写操作。
由于目标事务通常是由一个数据库操作序列构成的,即目标事务可能涉及到多个数据库操作,这些数据库操作也可能指向相同或不同的数据记录,例如,目标事务涉及到读取数据记录R1的V1版本,同时将数据记录R2从V1版本修改为V2版本,在传统锁机制的作用下,为了避免并发事务之间产生读写冲突导致不一致的问题,此时目标事务通常需要向全局的锁管理器发送锁申请请求,以在数据记录R1上申请一个读锁,在数据记录R2上申请一个写锁。
在本申请实施例中,涉及一种事务锁方案,由于不依赖于全局的锁管理器,因此计算设备只需要对该目标事务所涉及操作的每条数据记录,均基于下述步骤402涉及方式来进行锁申请的冲突检测,即可识别出真正存在冲突的目标事务,如果目标事务在冲突检测中发现实际上不存在冲突,那么无需对这些数据记录添加不必要的行锁,如果目标事务在冲突检测中发现存在冲突,才需要真正在对应数据记录上申请与操作类型对应的锁,比如,目标事务涉及读该条数据记录则申请读锁,目标事务涉及修改该条数据记录则申请写锁。
可选地,在InnoDB引擎中,由于每条数据记录中都会包含一个目标隐藏字段,该目标隐藏字段也即事务号(DB_TRX_ID)字段,计算设备对目标事务操作的每条数据记录,都能够从该数据记录的目标隐藏字段中读取到修改该数据记录的最新事务的事务ID,该事务ID能够唯一标识修改该数据记录的最新事务,这一最新事务的事务状态能够指示该数据记录的写锁信息,这是因为,如果该数据记录被添加了写锁,只能是最新事务添加的写锁,此时如果最新事务的事务状态是活跃状态,则代表最新事务持有该数据记录的写锁,如果最新事务的事务状态不是活跃状态,则代表最新事务上没有被添加任何写锁。
402、计算设备基于全局读锁信息和该最新事务的写锁等待信息,对该目标事务进行锁申请的冲突检测,该全局读锁信息用于管理数据库系统中的读锁,该写锁等待信息用于记录等待该最新事务所持有写锁的各个事务。
由于全局读锁信息中记载了整个数据库系统中的读锁的相关信息,其中,全局的读锁的相关信息包括:对系统内正在被读取的每条数据记录,都会记录下来哪些事务在当前时刻持有该数据记录上的读锁,以及哪些事务正在等待该数据记录上读锁的锁持有者释放掉该读锁。因此,对新到的一个目标事务,利用全局读锁信息就能够完成对目标事务的读锁冲突检测。
而进一步的,在上述步骤401中确定出修改该数据记录的最新事务之后,以该最新事务的事务ID为索引,能够在数据库系统的活跃事务列表(维护在内存中,通常以链表形式存在)查询得到该最新事务的事务状态(例如是一个State参数),如果最新事务的事务状态是活跃状态,即State=Active,则代表最新事务持有该数据记录的写锁,如果最新事务的事务状态不是活跃状态,即State≠Active,则代表该数据记录上没有被添加任何写锁。此外,由于在本申请实施例之前已经介绍过了,事务锁方案中在每个事务创建时初始化阶段,会对事务的上下文信息中新增一个哈希表字段来表示该事务的写锁等待信息,即记录有哪些事务正在等待该事务修改的数据记录上的写锁。因此,对新到的一个目标事务,利用其涉及操作的数据记录上事务号(DB_TRX_ID)字段所记载的事务ID所指示的最新事务的事务状态State,以及该最新事务自身在上下文信息中维护的写锁等待信息,就能够完成对目标事务的写锁冲突检测。
在一些实施例中,不管目标事务对该数据记录执行读操作还是写操作,均需要分别进行读锁冲突检测和写锁冲突检测,只有在读锁冲突检测和写锁冲突检测都通过(即不存在读锁冲突也不存在写锁冲突)的情况下,认为该目标事务通过冲突检测即不存在冲突,然后直接执行目标事务,并在执行完毕后进入验证阶段来判断是提交目标事务还是回滚目标事务,即针对不存在冲突的情况,不需要维护任何锁信息,能够大大降低数据库系统在高并发场景下创建的锁数量,针对一些不必要的行锁通过识别出来不存在冲突,就无需创建和维护这些不必要的行锁,从而节约了锁信息所带来的内存开销。
进一步的,如果读锁冲突检测未通过即存在读锁冲突,或者写锁冲突检测未通过即存在写锁冲突,那么需要目标事务进入锁等待阶段,即需要等待该条数据记录上已有锁的锁持有端释放锁资源之后,目标事务才能够排队申请在该数据记录上添加锁,这时需要维护一部分读锁等待信息或者写锁等待信息,以便于在数据记录上已有锁的锁持有端释放锁资源之后,唤醒正在等待的某个或者多个事务。
在上述过程中,对任何类型的目标事务都需要进行读锁冲突检测和写锁冲突检测,提供了较为完备的冲突检测逻辑。但是考虑到读锁是共享锁而非排它锁,因此如果目标事务对该数据记录所执行操作的操作类型是读操作,那么不管在该数据记录上是否已有读锁,那么目标事务均能够共享这把已有的读锁,相当于无论如何读锁冲突检测都会通过(即不可能存在读锁冲突),那么这种情况(指目标事务对数据记录申请读锁的情况)下,没必要执行读锁冲突检测。
换言之,计算设备基于目标事务对该数据记录所涉及的数据库操作的操作类型,确定该目标事务对该数据记录待申请的锁类型,接着,在该锁类型为读锁的情况下,无需执行读锁冲突检测,仅执行写锁冲突检测即可;在该锁类型为写锁的情况下,才需要既执行读锁冲突检测又执行写锁冲突检测,这样能够简化冲突检测流程,进一步避免资源浪费。
比如,假设事务T1涉及读取数据记录R1,事务T2涉及修改数据记录R2,那么事务T1在数据记录R1上待申请的锁类型为读锁,只需要对事务T1执行写锁冲突检测,事务T2在数据记录R2上待申请的锁类型为写锁,此时需要对事务T2执行读锁冲突检测和写锁冲突检测。
403、计算设备在该冲突检测指示存在冲突的情况下,申请对该数据记录添加与该操作的操作类型对应的锁。
在一些实施例中,在通过上述402对目标事务进行锁申请的冲突检测之后,能够得到一个冲突检测结果,例如该冲突检测结果是一个返回值,该返回值用于指示该目标事务在该数据记录上待申请的锁是否与该数据记录上的已有锁之间存在冲突。
可选地,该返回值可以是一个二值数据,当二值数据取值为1时代表存在冲突,未通过冲突检测;当二值数据取值为0时代表不存在冲突,通过冲突检测。
可选地,该返回值可以是一个布尔型数据,当布尔型数据取值为True时代表存在冲突,未通过冲突检测;当二值数据取值为False时代表不存在冲突,通过冲突检测。
在一些实施例中,当该返回值指示存在冲突时,认为冲突检测不通过,那么目标事务需要等待在该数据记录上的已有锁释放之后,才能够执行自身对该数据记录的数据库操作,此时这种情况才需要申请对该数据记录添加对应操作类型的锁,由于本次申请的锁与已有锁之间存在冲突,因此目标事务不能立即申请到锁,实际上目标事务会进入到锁等待阶段;反之,当返回值指示不存在冲突时,任务冲突检测通过,说明目标事务在该数据记录上所申请的锁实际上没有冲突,因此是不必要的行锁,此时只需要直接执行并提交(或回滚)目标事务即可,而不需要创建或维护任何锁信息,当然为了保证后续新到的其他事务的冲突检测不出错,只需要更新一些已有的参数即可,比如当目标事务修改了该数据记录,那么需要将目标事务的事务ID写入到该数据记录的事务号(DB_TRX_ID)字段。
下面针对高并发场景进行分析,在并发事务之间不存在冲突(即冲突检测通过)时,事务锁方案不需要对目标事务创建任何锁信息,极大节约了锁信息的维护和存储开销;在并发事务之间冲突较低、而单个事务所更新的数据记录条数较多时,事务锁方案使得整个数据库系统内创建锁的数量大大减少,从而使得内存占用大大减少;在并发事务之间冲突较高时,事务锁方案简化了原生InnoDB引擎行锁的加锁逻辑,避免了原生加锁逻辑中,无论是否存在冲突都需要获取全局锁管理器的互斥量所耗费的时间,从而能够大幅提升数据库系统内部的事务处理性能。
上述所有可选技术方案,能够采用任意结合形成本公开的可选实施例,在此不再一一赘述。
本申请实施例提供的方法,通过全局读锁信息记录数据库系统中的读锁的相关信息,通过修改每条数据记录的最新事务能够确定在该数据记录上是否存在写锁以及写锁的锁持有者,并且将写锁等待信息打散存储到每个事务的上下文信息中,使得整个数据库系统的读写冲突检测无需依赖于锁管理器,也无需每次访问互斥量,利用全局读锁信息和所欲操作的数据记录所对应最新事务的写锁等待信息完成冲突检测后,能够仅针对存在冲突的情况,才申请创建相应的锁信息,针对不存在冲突的情况则无需耗费资源来维护锁信息,能够极大减少系统内创建不必要的行锁,从而节约锁机制下并发控制的存储开销和内存占用。
在上一实施例中,简单介绍了本申请实施例涉及的事务锁方案总体的并发控制策略,而在本申请实施例和下一个实施例中,将分别针对目标事务对数据记录申请读锁以及目标事务对数据记录申请写锁这两种情况,分别介绍其总体的冲突检测流程,下面进行说明。
图5是本申请实施例提供的一种事务处理方法的流程图,如图5所示,该实施例由电子设备执行,该电子设备可以是数据库系统中的计算设备(即计算设备,SQL引擎)或者存储设备(即存储节点,即存储引擎),这里以电子设备为计算设备为例进行说明,该实施例包括下述步骤:
501、计算设备基于目标事务所操作的数据记录,确定修改该数据记录的最新事务。
上述步骤501与上述步骤401类似,这里不做赘述。
502、计算设备基于该操作的操作类型,确定该目标事务待申请的锁类型。
在一些实施例中,当目标事务对该数据记录所进行的操作(即数据库操作)的操作类型为读操作时,确定该目标事务对该数据记录待申请的锁类型为读锁;当目标事务对该数据记录所进行的操作(即数据库操作)的操作类型为写操作时,确定该目标事务对该数据记录待申请的锁类型为写锁。
在本申请实施例中,仅针对目标事务对该数据记录待申请的锁类型为读锁的情况,介绍其冲突检测流程、存在冲突情况下的锁申请流程和事务提交后的锁释放流程。而上述目标事务对该数据记录待申请的锁类型为写锁的情况,则在下一个实施例中进行详细说明,这里不做赘述。
503、计算设备在该锁类型为读锁的情况下,获取该最新事务的事务状态。
在该锁类型为读锁的情况下,仅需要对该目标事务进行写锁冲突检测,这是因为无论全局读锁信息(slock_table)中,该数据记录的Key-Value数据结构中的读锁持有队列(hold_que_read)和读锁等待队列(wait_que_read)中有没有元素,读锁冲突检测都能够通过,因此,即使读锁等待队列(wait_que_read)有元素(即存在等待事务),由于目标事务申请的读锁是共享锁,因此对数据记录的读锁也是能够申请成功的,说明不可能存在读锁冲突,即读锁冲突检测默认通过,因此也就不需要进行读锁冲突检测,在申请读锁时仅进行写锁冲突检测,将写锁冲突检测的检测结果作为整体的冲突检测结果即可。
在一些实施例中,在上述步骤501中确定出修改该数据记录的最新事务之后,以该最新事务的事务ID为索引,能够在数据库系统的活跃事务列表(维护在内存中,通常以链表形式存在)查询得到该最新事务的事务状态(例如是一个State参数),进入下述步骤504。
504、计算设备基于该最新事务的事务状态,确定冲突检测结果。
示意性地,该冲突检测结果是一个用于指示是否存在冲突的返回值。例如该返回值是二值数据,当二值数据取值为1时代表存在冲突,未通过冲突检测;当二值数据取值为0时代表不存在冲突,通过冲突检测。又例如,该返回值可以是一个布尔型数据,当布尔型数据取值为True时代表存在冲突,未通过冲突检测;当二值数据取值为False时代表不存在冲突,通过冲突检测。
在一些实施例中,在该最新事务的事务状态不是活跃状态的情况下,即最新事务的State≠Active,则代表该数据记录上目前没有被添加任何写锁,这时目标事务无需等待任何事务释放锁资源,因此将冲突检测结果确定为不存在冲突,以该冲突检测结果为返回值为例,此时将返回值的二值数据配置为0,或者将返回值的布尔型数据配置为False。
可选地,为保证后续其他事务的冲突检测不会出错,在上述不存在冲突的情况下,还需要在该全局读锁信息中,以该数据记录的记录标识为索引,查询该数据记录的读锁持有队列,其中,该全局读锁信息用于管理数据库系统中的读锁,该读锁持有队列用于记录持有该数据记录的读锁的各个事务。接着,判断该读锁持有队列中是否包含该目标事务,在该读锁持有队列中包含该目标事务的情况下,直接执行并提交(或回滚)目标事务即可,在该读锁持有队列中不包含该目标事务的情况下,则将该目标事务添加至该读锁持有队列。
在一个示例性场景中,由于该全局读锁信息是一张如图3所示的全局的哈希表slock_table,全局读锁信息slock_table中对整个数据库系统中正在被读取的每条数据记录都会创建一个Key-Value数据结构,对每条数据记录的Key-Value数据结构来说,Key(键名)为该数据记录的唯一记录标识(即记录ID),Value(键值)中则包含一个队列对(即包含两个队列),其中一个是读锁持有队列(hold_que_read),读锁持有队列用于记录持有该数据记录的读锁的各个事务的事务ID,另外一个是读锁等待队列(wait_que_read),读锁等待队列用于记录等待对该数据记录所持有读锁的各个事务的事务ID。因此,针对上述不存在冲突的情况,只需要以目标事务所操作的该数据记录的记录ID为索引,在全局读锁信息slock_table中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的读锁持有队列(hold_que_read),判断该读锁持有队列(hold_que_read)中是否已经包含目标事务的事务ID,如果读锁持有队列(hold_que_read)中已经包含了目标事务的事务ID,直接执行并提交(或回滚)目标事务即可,如果读锁持有队列(hold_que_read)中不包含目标事务的事务ID,则将目标事务的事务ID添加至该读锁持有队列(hold_que_read)中。
在一些实施例中,在该最新事务的事务状态是活跃状态的情况下,即最新事务的State=Active,则代表最新事务持有该数据记录的写锁,即代表了目标事务所欲在该数据记录上申请的读锁与最新事务在该数据记录上正在持有的写锁之间产生了冲突,因此将该冲突检测结果确定为存在冲突,以该冲突检测结果为返回值为例,此时将返回值的二值数据配置为1,或者将返回值的布尔型数据配置为True。
可选地,为了避免发生读写冲突带来的数据异常,此时后到的目标事务需要等待最新事务是否掉该数据记录上的锁资源,才能够尝试申请在该数据记录上添加新的写锁(即尝试申请持有该数据记录上新的写锁),不过由于可能目标事务之前还会存在其他同样在等待最新事务的其他事务,因此需要对最新事务维护一个写锁等待信息,以记录下来哪些事务在等待该最新事务对哪些数据记录所持有的写锁,以便于在最新事务提交后决策是否需要唤醒正在等待该最新事务的某个或多个事务。事务锁方案中在每个事务创建时初始化阶段,会对事务的上下文信息中新增一个哈希表字段来表示该事务的写锁等待信息,即记录有哪些事务正在等待该事务修改的数据记录上的写锁。
因此,在存在冲突的情况下,需要将目标事务添加到最新事务的写锁等待信息中,可选地,计算设备可以基于该最新事务的事务ID,在内存中访问到该最新事务的上下文信息,并查询该最新事务的上下文信息中写锁等待信息所处的哈希表字段,既能够访问该最新事务的写锁等待信息。其中,该写锁等待信息用于记录等待该最新事务所持有写锁的各个事务,由于该最新事务可能操作多条数据记录,而等待该最新事务的不同事务可能等待的是不同数据记录上的锁资源,因此在该写锁等待信息中为最新事务操作的每条数据记录维护一个写锁等待队列,换言之,该最新事务的写锁等待信息包括该最新事务所操作的每条数据记录的写锁等待队列,每条数据记录的写锁等待队列用于记录等待该最新事务对对应的数据记录所持有写锁的各个事务。接着,计算设备在该最新事务的写锁等待信息中,将该目标事务添加至该目标事务所操作的数据记录的写锁等待队列。
在一个示例性场景中,对该最新事务维护的写锁等待信息如图2所示,计算设备访问该最新事务的上下文信息中的哈希表字段(TRX_LOCK_WAIT),以访问该最新事务的写锁等待信息。接着,以该目标事务所操作的数据记录的记录ID为索引,在该写锁等待信息中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的写锁等待队列(wait_que_write),并将目标事务的事务ID添加至该写锁等待队列(wait_que_write)中。
进一步的,在存在冲突的情况下,计算设备除了将目标事务添加到最新事务的写锁等待信息中之外,还将该目标事务的阻塞事务参数(blocking_trx)设置为该最新事务的事务标识,该阻塞事务参数(blocking_trx)用于表征该目标事务所等待的事务,即,相当于令目标事务的blocking_trx=最新事务的事务ID,表示目标事务正在等待最新事务,从而能够利用每个事务的阻塞事务参数(blocking_trx)来执行整个数据库系统的死锁检测流程,以便于及时发现系统内陷入死锁的事务。
505、计算设备在该冲突检测结果为存在冲突的情况下,申请对该数据记录添加与该操作的操作类型对应的锁即读锁。
上述步骤505与上述步骤403类似,即,在冲突检测结果为存在冲突的情况下,虽然目标事务尝试申请该数据记录上的锁资源,但是由于发生冲突,使得目标事务进入锁等待阶段,即需要等待最新事务释放掉在该数据记录上持有的写锁之后,目标事务才能够排队申请在该数据记录上添加新的读锁,在排队轮到目标事务且锁申请成功后,目标事务执行并提交(或回滚),然后释放目标事务自身申请到的读锁,唤醒下一个请求在该数据记录执行操作的事务(当然由于读锁是共享锁,目标事务读完毕之后可能存在其他持有该读锁的事务没有读完,此时无需进行事务唤醒),相关流程将在下述步骤507至508-A或508-B或508-C中进行说明,这里不做赘述。
在一些实施例中,上述步骤505涉及的是计算设备在冲突检测结果为存在冲突的情况下申请锁,而在该冲突检测结果为不存在冲突的情况下,计算设备无需维护任何锁信息,直接进入下述步骤506执行该目标事务即可。
506、计算设备在目标事务对该数据记录添加锁成功之后,执行该目标事务。
在本申请实施例中涉及对该数据记录申请读锁,在对该数据记录的读锁申请成功后,目标事务读取该数据记录,即对该数据记录实现读操作,例如,读取该数据记录的最新可见的变量版本。
在一些实施例中,由于目标事务可能是一系列数据库操作构成的操作序列,因此有可能目标事务涉及操作多条数据记录,目标事务对每条数据记录均执行完毕对应的数据库操作之后,才能够进入目标事务的验证阶段,即验证该目标事务是否能够进行提交,如果发现了数据异常则验证不通过,需要对目标事务进行回滚,如果没有发现数据异常,那么可以提交该目标事务。
需要说明的是,在目标事务涉及操作多条数据记录,并且对不同数据记录的操作类型也不同时,对于读操作使用本申请实施例的方法来进行冲突检测,并在申请锁成功(或者通过冲突检测无需申请锁)时对对应数据记录实现读操作,对于写操作则使用下一个实施例中的方法来进行冲突检测,并在申请锁成功(或者通过冲突检测无需申请锁)时对对应数据记录实现写操作,等待目标事务所操作的所有数据记录均执行完毕对应操作之后,才能够进入目标事务的验证阶段和提交阶段(或回滚阶段),这里不做赘述。
507、计算设备在该目标事务提交后,在该全局读锁信息中,以该数据记录的记录标识为索引,查询该数据记录的读锁持有队列。
其中,该读锁持有队列用于记录持有该数据记录的读锁的各个事务。
在一些实施例中,如果目标事务通过了验证,并成功提交,那么还需要进行一些读锁的相关信息的更新修改,以释放掉目标事务对该数据记录所申请的读锁,并判断是否需要唤醒下一个需要对该数据记录执行操作的正在等待的事务,当然,由于读锁是共享锁,目标事务对该数据记录读操作完毕并提交之后,可能存在其他持有该读锁的事务没有读完或者尚未提交,此时无需进行事务唤醒。
在一些实施例中,目标事务提交完毕后,以目标事务所操作(即读取完毕)的该数据记录的记录ID为索引,在全局读锁信息slock_table中查询该索引所命中的Key-Value数据结构,然后访问索引命中的该Key-Value数据结构的Value中存储的读锁持有队列(hold_que_read),接着,判断该读锁持有队列(hold_que_read)是否为空,如果该读锁持有队列(hold_que_read)为空,进入下述步骤508-A;如果该读锁持有队列(hold_que_read)不为空,进一步判断该读锁持有队列(hold_que_read)中元素个数是否为1,如果该读锁持有队列(hold_que_read)的元素个数为1,那么还需要访问索引命中的该Key-Value数据结构的Value中存储的读锁等待队列(wait_que_read),判断该读锁持有队列(hold_que_read)中唯一的元素(必定是一个事务ID)是否恰好是读锁等待队列(wait_que_read)的第一个元素,代表读锁等待队列(wait_que_read)中的第一个正在等待的事务持有目前唯一的这把读锁,因此能够唤醒这一事务,进入下述步骤508-B;否则,如果不满足上述任一情况,例如,该读锁持有队列(hold_que_read)的元素个数大于1,或者虽然该读锁持有队列(hold_que_read)的元素个数为1但是这一元素并非是读锁等待队列(wait_que_read)的第一个元素,那么不需要唤醒任何正在等待的事务,进入下述步骤508-C。
508-A、在该读锁持有队列为空的情况下,计算设备唤醒该数据记录的读锁等待队列中的第一个事务。
其中,该读锁等待队列用于记录等待对该数据记录所持有读锁的各个事务。
在一些实施例中,如果该数据记录的读锁持有队列(hold_que_read)为空,代表目前没有任何事务持有该数据记录上的锁,因此需要唤醒该数据记录的读锁等待队列(wait_que_read)中的第一个事务,即,访问该数据记录的读锁等待队列(wait_que_read)中第一个元素所记录的事务ID,然后唤醒该事务ID所指示的事务(即读锁等待队列的第一个事务)。
显然,由于读锁是共享锁,如果一个事务被添加到了该数据记录的读锁等待队列(wait_que_read)中,那么这一事务必定申请的是对该数据记录的写锁,因为如果申请的是读锁且不存在冲突的话可以直接申请成功,因此,在本步骤508-A中唤醒的该读锁等待队列(wait_que_read)中的第一个事务,必定是一个写事务(即申请的是写锁,一定对该数据记录执行写操作),因此,针对被目标事务唤醒的事务(简称为唤醒的事务,在本步骤508-A的情况下是指读锁等待队列的第一个事务),在该唤醒的事务的写锁等待信息中,需要将该读锁等待队列(wait_que_read)中除了该唤醒的事务之外的各个事务添加至该数据记录的写锁等待队列(wait_que_write)中。
换言之,针对被目标事务唤醒的该读锁等待队列(wait_que_read)中的第一个事务,需要根据该第一个事务的事务ID,在内存中访问该第一个事务的上下文信息中的哈希表字段(TRX_LOCK_WAIT),以访问该第一个事务的写锁等待信息。接着,以该读锁等待队列(wait_que_read)所对应的该操作记录的记录ID为索引,在该写锁等待信息中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的写锁等待队列(wait_que_write),并将该读锁等待队列(wait_que_read)中剩余的所有事务ID均挂载到该写锁等待队列(wait_que_write)中,其中,由于唤醒的事务是第一个事务,因此该剩余的所有事务ID是指该读锁等待队列(wait_que_read)中第二个以及第二个以后的所有元素中存储的各个事务ID。
进一步的,由于目标事务已经提交完毕了,此时新添加到上述写锁等待队列(wait_que_write)中的每个事务,其等待的对象发生了改变(即原本在等目标事务,现在目标事务提交后唤醒了该第一个事务,因此现在是在等第一个事务),为了避免死锁检测出错,避免被添加到上述写锁等待队列(wait_que_write)中的每个事务的阻塞事务参数(blocking_trx)中记载的是已经提交完毕的目标事务的事务ID,因此,还对这些剩余的等待事务的阻塞事务参数(blocking_trx)进行更新。
可选地,在将读锁等待队列(wait_que_read)中剩余的所有事务ID均挂载到该写锁等待队列(wait_que_write)之后,计算设备对添加到该写锁等待队列(wait_que_write)中的任一事务,将该事务的阻塞事务参数(blocking_trx)设置为该唤醒的事务的事务标识,该阻塞事务参数(blocking_trx)用于表征该事务所等待的事务,即,相当于令该事务的blocking_trx=唤醒的该读锁等待队列(wait_que_read)中的第一个事务的事务ID,表明这些剩余的等待事务现在都在等待被唤醒的该第一事务,从而保证了数据库系统死锁检测的正确性。
508-B、在该读锁持有队列仅包含单个事务,且该事务恰好是该读锁等待队列中的第一个事务的情况下,计算设备唤醒该事务。
在一些实施例中,如果该数据记录的读锁持有队列(hold_que_read)的元素个数为1,并且该读锁持有队列(hold_que_read)中唯一的元素(必定是一个事务ID)是否恰好是读锁等待队列(wait_que_read)的第一个元素,换言之,该读锁持有队列(hold_que_read)仅包含单个事务,并且读锁等待队列(wait_que_read)中正在等待的第一个事务恰好持有这把唯一的读锁,那么这个显然能够继承这把读锁,此时可以唤醒该事务(即指该读锁持有队列中包含的这个唯一的事务,也等于读锁等待队列中的第一个事务)。
本步骤508-B中唤醒该事务的方式与上述步骤508-A中唤醒事务的方式类似,这里不做赘述。
同理,针对本步骤508-B的情况下唤醒的事务,同样需要在该唤醒的事务的写锁等待信息中,将该读锁等待队列中除了该唤醒的事务之外的各个事务添加至该数据记录的写锁等待队列,即更新唤醒的事务的写锁等待信息,向写锁等待队列中添加事务的方式与上述步骤508-A类似,这里不做赘述。
同理,针对上述从读锁等待队列添加到唤醒的事务中对应写锁等待队列中的事务,同样需要对添加到该写锁等待队列中的任一事务,将该事务的阻塞事务参数设置为该唤醒的事务的事务标识,该阻塞事务参数用于表征该事务所等待的事务,即更新剩余的等待事务的阻塞事务参数,更新阻塞事务参数的方式与上述步骤508-A类似,这里不做赘述。
508-C、否则即在不满足508-A或508-B的情况下,计算设备对该读锁等待队列中的每个事务,将该事务的阻塞事务参数设置为该读锁持有队列中除了该事务之外的第一个事务的事务标识。
其中,该阻塞事务参数用于表征该事务所等待的事务。
在一些实施例中,如果该读锁持有队列(hold_que_read)的元素个数大于1,或者虽然该读锁持有队列(hold_que_read)的元素个数为1但是这一元素并非是读锁等待队列(wait_que_read)的第一个元素,那么既不满足508-A也不满足508-B,此时不需要唤醒任何正在等待的事务,只需要更新全局读锁信息中本条数据记录的读锁等待队列(wait_que_read)中各个事务的阻塞事务参数(blocking_trx)即可,换言之确保读锁等待队列(wait_que_read)中各个事务的阻塞事务参数(blocking_trx)在更新后不是已经提交的目标事务的事务标识。
示意性地,在目标事务提交后,如果判断既不满足508-A也不满足508-B,此时计算设备遍历该读锁等待队列(wait_que_read)中的每个事务,将该事务的阻塞事务参数(blocking_trx)设置为该读锁持有队列(hold_que_read)中第一个不等于自己的事务的事务ID,以保证这些还在等待的事务都不再等待已经提交的目标事务,同时还保证了这些还在等待的事务不会自己等自己(例如事务A等待事务A)导致陷入死锁,从而保证了数据库系统死锁检测的正确性。
上述所有可选技术方案,能够采用任意结合形成本公开的可选实施例,在此不再一一赘述。
本申请实施例提供的方法,通过在目标事务对数据记录申请读锁的情况下,仅对目标事务进行写锁冲突检测,这一写锁冲突检测无需依赖于锁管理器,也无需每次访问互斥量,能够加快锁申请的流程,并且,仅在写锁冲突检测未通过即存在冲突的情况下,才申请创建相应的锁信息,针对不存在冲突的情况则无需耗费资源来维护锁信息,能够极大减少系统内创建不必要的行锁,从而节约锁机制下并发控制的存储开销和内存占用。
在上一实施例中,介绍了目标事务对数据记录申请读锁的情况下,仅执行写锁冲突检测的检测逻辑,以及在目标事务提交后释放申请到的读锁的释放锁逻辑,而在本申请实施例中,将详细介绍目标事务对数据记录申请写锁的情况下,既进行读锁冲突检测也进行写锁冲突检测,并且还会介绍在目标事务提交后释放申请到的写锁的释放锁逻辑,下面进行说明。
图6是本申请实施例提供的一种事务处理方法的流程图,如图6所示,该实施例由电子设备执行,该电子设备可以是数据库系统中的计算设备(即计算设备,SQL引擎)或者存储设备(即存储节点,即存储引擎),这里以电子设备为计算设备为例进行说明,该实施例包括下述步骤:
601、计算设备基于目标事务所操作的数据记录,确定修改该数据记录的最新事务。
上述步骤601与上述步骤501类似,这里不做赘述。
602、计算设备基于该操作的操作类型,确定该目标事务待申请的锁类型。
上述步骤602与上述步骤502类似,这里不做赘述。
在本申请实施例中,仅针对目标事务对该数据记录待申请的锁类型为写锁的情况,介绍其冲突检测流程、存在冲突情况下的锁申请流程和事务提交后的锁释放流程,此时计算设备需要对该目标事务进行读锁冲突检测和写锁冲突检测。
603、计算设备在该锁类型为写锁的情况下,对该目标事务进行读锁冲突检测。
在一些实施例中,在进行读锁冲突检测时,使用如图3所示的哈希表形式的全局读锁信息slock_table来实现读锁冲突检测,全局读锁信息slock_table的数据结构已经在上一实施例中介绍过了,这里不再赘述。
可选地,在读锁冲突检测过程中,计算设备在该全局读锁信息中,以该数据记录的记录标识为索引,查询该数据记录的读锁持有队列,其中,该读锁持有队列用于记录持有该数据记录的读锁的各个事务,换言之,计算设备以目标事务所操作的该数据记录的记录ID为索引,在全局读锁信息slock_table中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的读锁持有队列(hold_que_read)。
针对上述访问的该数据记录的读锁持有队列(hold_que_read),如果该读锁持有队列(hold_que_read)为空,即该读锁持有队列(hold_que_read)没有任何元素,进入下述情况1;如果该读锁持有队列(hold_que_read)不为空,则包括2-1和2-2两种情况:如果该读锁持有队列(hold_que_read)仅包含一个事务且这个事务就是目标事务自己,进入情况2-1;如果该读锁持有队列(hold_que_read)中包含不止一个事务,或者该读锁持有队列(hold_que_read)仅包含一个事务但这个事务不是目标事务自己,进入情况2-2,下面将针对各种情况下的读锁冲突检测逻辑进行介绍。
情况1、该读锁持有队列(hold_que_read)为空
即,该读锁持有队列(hold_que_read)中没有任何元素,此时本数据记录的记录ID命中的该Key-Value数据结构的Value中存储的读锁等待队列(wait_que_read)肯定也没有任何正在等待的事务,返回不存在读锁冲突,说明读锁冲突检测通过,进入下述步骤605,开启写锁冲突检测。
情况2-1、该读锁持有队列(hold_que_read)仅包含该目标事务
这一情况2-1等价于:该读锁持有队列(hold_que_read)仅包含一个事务且这个事务就是目标事务自己,此时相当于该读锁持有队列(hold_que_read)仅包含目标事务,此时,计算设备需要继续查询本数据记录的记录ID命中的该Key-Value数据结构的Value中存储的读锁等待队列(wait_que_read),该读锁等待队列(wait_que_read)用于记录等待对该数据记录所持有读锁的各个事务。
接着,在该读锁等待队列(wait_que_read)为空的情况下,说明该读锁等待队列(wait_que_read)中没有记载任何正在等待的事务,说明目标事务申请了写锁并目标事务还持有了该条数据记录上唯一的一把读锁,因此目标事务显然能够继承这把读锁,从而返回不存在读锁冲突,说明读锁冲突检测通过,进入下述步骤605,开启写锁冲突检测。
此外,在该读锁等待队列(wait_que_read)不为空的情况下,说明还有其他事务正在等待该条数据记录上的读锁,这时目标事务不能继承这把读锁,目标事务需要等待该读锁等待队列(wait_que_read)中已有事务提交或回滚后,才能够持有本次申请的写锁,因此返回存在读锁冲突,说明读锁冲突检测不通过,进入下述步骤604。
针对上述该读锁等待队列(wait_que_read)不为空的情况,由于目标事务需要等待即进入锁等待阶段,因此还需要将该目标事务添加至该条数据记录的读锁等待队列,换言之,将该目标事务的事务ID插入到当前访问的不为空的该读锁等待队列(wait_que_read)中。
此外,由于目标事务对该条数据记录申请的是写锁,代表目标事务是一个写事务,因此目标事务会在内存中其事务的上下文信息中维护自身的写锁等待信息,此时计算设备还需要将写锁等待信息中指示的所有正在等待该目标事务的各个事务也添加到该读锁等待队列(wait_que_read)中,换言之,计算设备访问该目标事务自己的上下文信息中的哈希表字段(TRX_LOCK_WAIT),以访问该目标事务的写锁等待信息。接着,以该目标事务所操作的数据记录的记录ID为索引,在该写锁等待信息中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的写锁等待队列(wait_que_write),接着,将整个写锁等待队列(wait_que_write)都一起挂载到该条数据记录在全局读锁信息slock_table中的该读锁等待队列(wait_que_read)中。上述过程也相当于,基于该目标事务的写锁等待信息中该条数据记录的写锁等待队列(wait_que_write),确定等待该目标事务对该数据记录所申请写锁的各个事务,然后将该等待该目标事务对该数据记录所申请写锁的各个事务添加到该读锁等待队列(wait_que_read)。
进一步的,在上述将目标事务自身事务ID以及目标事务针对该条数据记录的整个写锁等待队列(wait_que_write)都挂载到该条数据记录的读锁等待队列(wait_que_read)之后,需要对添加到该读锁等待队列(wait_que_read)中的任一事务(包括目标事务以及目标事务的写锁等待队列中的每个事务),都需要对该事务的阻塞事务参数(blocking_trx)进行更新,其中,该阻塞事务参数(blocking_trx)用于表征该事务所等待的事务。
上述对阻塞事务参数(blocking_trx)的更新方式包括:将每个事务的阻塞事务参数(blocking_trx)设置为该读锁持有队列(hold_que_read)中除了该事务之外的第一个事务的事务标识,换言之,令该事务的blocking_trx=读锁持有队列(hold_que_read)中第一个不等于自己的事务的事务ID,表明这些被挂载到该读锁等待队列(wait_que_read)的新的事务,都在等待目前在该数据记录上已有的这把读锁,并且还保证了这些事务不会自己等自己(例如事务A等待事务A)导致陷入死锁,从而保证了数据库系统死锁检测的正确性。
情况2-2、该读锁持有队列(hold_que_read)包含除了该目标事务之外的事务
这一情况2-2等价于:该读锁持有队列(hold_que_read)中包含不止一个事务,或者该读锁持有队列(hold_que_read)仅包含一个事务但这个事务不是目标事务自己。
在上述情况2-2中,目标事务同样需要等待该读锁持有队列(hold_que_read)中除了自己之外的事务释放掉目前已有的读锁之后,才能够持有本次申请的写锁(当然也需要按照读锁等待队列中的写入顺序来排队申请),因此返回存在读锁冲突,说明读锁冲突检测不通过,进入下述步骤604。
针对上述该读锁持有队列(wait_que_read)包含除了该目标事务之外的事务的情况,同样需要将目标事务自身事务ID以及目标事务针对该条数据记录的整个写锁等待队列(wait_que_write)都挂载到该条数据记录的读锁等待队列(wait_que_read),也同样需要对添加到该读锁等待队列(wait_que_read)中的任一事务(包括目标事务以及目标事务的写锁等待队列中的每个事务),都需要对该事务的阻塞事务参数(blocking_trx)进行更新,与上面情况2-1中涉及的该读锁等待队列(wait_que_read)不为空的情况下的挂载方式和更新方式类似,这里不做赘述。
604、在该读锁冲突检测指示存在读锁冲突的情况下,将冲突检测结果确定为存在冲突,进入步骤607。
示意性地,该冲突检测结果是一个用于指示是否存在冲突的返回值。例如该返回值是二值数据,当二值数据取值为1时代表存在冲突,未通过冲突检测;当二值数据取值为0时代表不存在冲突,通过冲突检测。又例如,该返回值可以是一个布尔型数据,当布尔型数据取值为True时代表存在冲突,未通过冲突检测;当二值数据取值为False时代表不存在冲突,通过冲突检测。
在一些实施例中,如果读锁冲突检测指示存在读锁冲突,即在上述步骤603进行读锁冲突检测的过程中,当满足情况2-1且对应数据记录的读锁等待队列(wait_que_read)不为空,或者,满足情况2-2时,均会返回存在读锁冲突,说明读锁冲突检测不通过,代表目标事务所欲在该数据记录上申请的写锁与该数据记录上已有的读锁之间产生了冲突,因此将该冲突检测结果确定为存在冲突,以该冲突检测结果为返回值为例,此时将返回值的二值数据配置为1,或者将返回值的布尔型数据配置为True。此时,无需执行写锁冲突检测流程,直接跳转至步骤607。
605、在该读锁冲突检测指示不存在读锁冲突的情况下,对该目标事务进行写锁冲突检测。
在一些实施例中,如果读锁冲突检测指示不存在读锁冲突,即在上述步骤603进行读锁冲突检测的过程中,当满足情况1,或者满足情况2-1且对应数据记录的读锁等待队列(wait_que_read)为空时,均会返回不存在读锁冲突,说明读锁冲突检测通过,此时还需要检测目标事务所欲在该数据记录上申请的写锁是否会与该数据记录已有的写锁之间产生冲突,即,对目标事务开启写锁冲突检测流程。
在一些实施例中,写锁冲突检测流程包括:计算设备获取该最新事务的事务状态,上述获取最新事务的事务状态的方式与上一实施例中的步骤503类似,这里不再赘述;接着,基于该最新事务的事务状态,确定是否存在写锁冲突,这一确定是否存在写锁冲突的方式与上一实施例中的步骤504类似,这里不再赘述。
在一些实施例中,在该最新事务的事务状态是活跃状态的情况下,即最新事务的State=Active,则代表最新事务持有该数据记录的写锁,即代表了目标事务所欲在该数据记录上申请的写锁与最新事务在该数据记录上正在持有的写锁之间产生了冲突,因此返回存在写锁冲突,进入下述步骤606。
进一步的,在上述该事务状态是活跃状态即State=Active的情况下,由于目标事务所欲在该数据记录上申请的写锁与最新事务在该数据记录上正在持有的写锁之间产生了冲突,说明目标事务需要等待该最新事务提交后才有可能申请到在该数据记录上的写锁,因此,还需要对该最新事务的写锁等待信息进行更新,即,需要将目标事务以及等待该目标事务的对该数据记录所申请写锁的各个事务,均挂载到该最新事务的写锁等待信息中与该数据记录对应的写锁等待队列(wait_que_write)中,其中,该最新事务的写锁等待信息包括该最新事务所操作的每条数据记录的写锁等待队列,该写锁等待队列用于记录等待该最新事务对该数据记录所持有写锁的各个事务。
也即是说,上述对该写锁等待信息的更新方式包括:计算设备基于最新事务的事务ID,在内存中访问该最新事务的上下文信息中的哈希表字段(TRX_LOCK_WAIT),以访问该最新事务的写锁等待信息。
接着,以该目标事务所欲操作的数据记录的记录ID为索引,在该最新事务的写锁等待信息中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的写锁等待队列(wait_que_write),然后将目标事务自身的事务ID添加到访问的该写锁等待队列(wait_que_write)中,相当于将该目标事务添加至该数据记录的写锁等待队列(wait_que_write)。
接着,通过上述与访问最新事务的写锁等待信息类似的方式,访问该目标事务的写锁等待信息,以该目标事务所欲操作的数据记录的记录ID为索引,在该目标事务的写锁等待信息中同样查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的写锁等待队列(wait_que_write),这一写锁等待队列(wait_que_write)即用于指示等待该目标事务对该数据记录所申请写锁的各个事务;然后在该最新事务的写锁等待信息中,将访问的该目标事务对该数据记录的写锁等待队列(wait_que_write)整个挂载到最新事务中对应数据记录的写锁等待队列(wait_que_write)中,相当于将该等待该目标事务对该数据记录所申请写锁的各个事务添加到该最新事务对该数据记录的写锁等待队列(wait_que_write)。
进一步的,在将目标事务自己以及目标事务的写锁等待信息中该条数据记录的写锁等待队列(wait_que_write)一起挂载到最新事务的写锁等待信息中同一数据记录的写锁等待队列(wait_que_write)之后,还需要对所有新添加过去的每个事务(包括目标事务以及目标事务的写锁等待队列中的每个事务),更新该事务的阻塞事务参数(blocking_trx),其中,该阻塞事务参数(blocking_trx)用于表征该事务所等待的事务。
上述对阻塞事务参数(blocking_trx)的更新方式包括:将每个事务的阻塞事务参数(blocking_trx)设置为该最新事务的事务标识(即事务ID),换言之由于最新事务处于活跃状态,代表最新事务尚未提交,因此目标事务以及正在等待目标事务的所有事务都需要等待该最新事务,因此直接将阻塞事务参数(blocking_trx)更新成最新事务的事务ID即可保证死锁检测的正确性。
在一些实施例中,在该最新事务的事务状态不是活跃状态的情况下,即最新事务的State≠Active,则代表该数据记录上目前没有被添加任何写锁,这时目标事务无需等待任何事务释放锁资源,因此返回不存在写锁冲突,由于写锁冲突只有在不存在读锁冲突的情况下才会开启,此时说明既不存在读锁冲突也不存在写锁冲突,即代表读锁冲突检测和写锁冲突检测都通过了,那么直接将该冲突检测结果确定为不存在冲突,以该冲突检测结果为返回值为例,此时将返回值的二值数据配置为0,或者将返回值的布尔型数据配置为False,然后进入步骤608中直接执行目标事务即可。
进一步的,在上述该事务状态不是活跃状态即State≠Active的情况下,还需要在该数据记录上更新事务号(DB_TRX_ID)字段中记录的事务ID,将原本该事务号(DB_TRX_ID)字段记录的是最新事务的事务ID,现在要将目标事务的事务ID写入到事务号(DB_TRX_ID)字段中,即,原本的最新事务已经不是活跃状态了,说明原本的最新事务要么已提交要么已回滚,当前的目标事务变成了正在修改该数据记录的最新事务。也即是说,计算设备在该目标事务所操作的该数据记录的目标隐藏字段(即DB_TRX_ID字段)中,写入该目标事务的事务标识(事务ID),其中,该目标隐藏字段(即DB_TRX_ID字段)用于记录修改该数据记录的最新事务的事务标识。
606、计算设备在该写锁冲突检测指示存在写锁冲突的情况下,将该冲突检测结果确定为存在冲突,进入步骤607。
示意性地,该冲突检测结果是一个用于指示是否存在冲突的返回值。例如该返回值是二值数据,当二值数据取值为1时代表存在冲突,未通过冲突检测;当二值数据取值为0时代表不存在冲突,通过冲突检测。又例如,该返回值可以是一个布尔型数据,当布尔型数据取值为True时代表存在冲突,未通过冲突检测;当二值数据取值为False时代表不存在冲突,通过冲突检测。
在一些实施例中,如果写锁冲突检测指示存在写锁冲突,即在上述步骤605进行写锁冲突检测的过程中,发现最新事务处于活跃状态,此时返回存在写锁冲突,说明写锁冲突检测不通过,代表目标事务所欲在该数据记录上申请的写锁与该数据记录上已有的写锁之间产生了冲突,因此将该冲突检测结果确定为存在冲突,以该冲突检测结果为返回值为例,此时将返回值的二值数据配置为1,或者将返回值的布尔型数据配置为True,进入步骤607。
607、计算设备在该冲突检测结果为存在冲突的情况下,申请对该数据记录添加与该操作的操作类型对应的锁即写锁。
上述步骤607与上述步骤505类似,即,在冲突检测结果为存在冲突的情况下,虽然目标事务尝试申请该数据记录上的锁资源,但是由于发生冲突,使得目标事务进入锁等待阶段,即需要等待该数据记录上已有的锁资源释放之后,目标事务才能够排队申请在该数据记录上添加新的写锁,在排队轮到目标事务且锁申请成功后,目标事务执行并提交(或回滚),然后释放目标事务自身申请到的写锁,唤醒下一个请求在该数据记录执行操作的事务(可能是读事务也可能是写事务),相关流程将在下述步骤609至610A-B中进行说明,这里不做赘述。
在一些实施例中,上述步骤607涉及的是计算设备在冲突检测结果为存在冲突的情况下申请锁,而在该冲突检测结果为不存在冲突的情况下,计算设备无需维护任何锁信息,直接进入下述步骤608执行该目标事务即可。
608、计算设备在目标事务对该数据记录添加锁成功之后,执行该目标事务。
在本申请实施例中涉及对该数据记录申请写锁,在对该数据记录的写锁申请成功后,目标事务才能够修改该数据记录,即对该数据记录实现写操作,例如,修改该数据记录中C1字段的取值,生成该数据记录的一个新的变量版本,同时版本号加一。
在一些实施例中,由于目标事务可能是一系列数据库操作构成的操作序列,因此有可能目标事务涉及操作多条数据记录,目标事务对每条数据记录均执行完毕对应的数据库操作之后,才能够进入目标事务的验证阶段,即验证该目标事务是否能够进行提交,如果发现了数据异常则验证不通过,需要对目标事务进行回滚,如果没有发现数据异常,那么可以提交该目标事务。
需要说明的是,在目标事务涉及操作多条数据记录,并且对不同数据记录的操作类型也不同时,对于写操作使用本申请实施例的方法来进行冲突检测,并在申请锁成功(或者通过冲突检测无需申请锁)时对对应数据记录实现写操作,对于读操作则使用上一个实施例中的方法来进行冲突检测,并在申请锁成功(或者通过冲突检测无需申请锁)时对对应数据记录实现读操作,等待目标事务所操作的所有数据记录均执行完毕对应操作之后,才能够进入目标事务的验证阶段和提交阶段(或回滚阶段),这里不做赘述。
609、计算设备在该目标事务提交后,遍历该目标事务的写锁等待信息中每条数据记录的写锁等待队列。
其中,该写锁等待队列用于记录等待该目标事务对该数据记录所持有写锁的各个事务。
在一些实施例中,计算设备访问该目标事务的上下文信息中的哈希表字段(TRX_LOCK_WAIT),以访问该目标事务的写锁等待信息,由于目标事务可能操作多条数据记录,因此目标事务的写锁等待信息中可能包含多条数据记录各自对应的写锁等待队列(wait_que_write),此时,计算设备遍历该目标事务的写锁等待信息中每个Key-Value数据结构中Value内存储的对应数据记录的写锁等待队列(wait_que_write),然后对每个写锁等待队列(wait_que_write),由于该写锁等待队列(wait_que_write)的第一个事务可能请求的读锁,也可能请求的写锁,对于读锁和写锁需要唤醒的事务数量不同。因此,计算设备需要判断该写锁等待队列(wait_que_write)的第一个事务申请的锁类型的读锁还是写锁,如果该写锁等待队列(wait_que_write)的第一个事务申请的锁类型是读锁,进入步骤610-B;如果该写锁等待队列(wait_que_write)的第一个事务申请的锁类型是写锁,进入步骤610-A。
610-A、对任一数据记录的写锁等待队列,计算设备在该写锁等待队列的第一个事务申请的锁类型为写锁的情况下,唤醒该第一个事务。
如果该写锁等待队列(wait_que_write)的第一个事务申请的锁类型是写锁,由于写锁是排它锁,因此只能唤醒该写锁等待队列(wait_que_write)的第一个事务,对于被唤醒的该第一个事务,还需要更新其写锁等待信息以及等待该第一个事务的各个事务的阻塞事务参数(blocking_trx)。
在一些实施例中,计算设备访问该第一个事务的上下文信息中的哈希表字段(TRX_LOCK_WAIT),以访问该第一个事务的写锁等待信息,接着,以当前遍历到的该数据记录的记录ID为索引,在该第一个事务的写锁等待信息中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的写锁等待队列(wait_que_write),接着,将针对目标事务当前遍历到的写锁等待队列(wait_que_write)中除了该第一个事务之外的各个事务添加到索引命中的Value中存储的对该数据记录的写锁等待队列(wait_que_write)中,换言之,在唤醒了该第一个事务之后,需要将原本还在等目标事务对该条数据记录释放写锁的各个事务(即原本写锁等待队列中第二个以及第二个以后的所有事务)全都挂载到被唤醒的该第一个事务对应的写锁等待队列(wait_que_write)中。
进一步的,在将原本写锁等待队列中剩余的所有事务(即第二个以及第二个以后的所有事务)都挂载到被唤醒的该第一个事务对应的写锁等待队列(wait_que_write)中之后,还需要对新添加到该写锁等待队列(wait_que_write)中的任一事务,更新其阻塞事务参数(blocking_trx),其中该阻塞事务参数(blocking_trx)用于表征该事务所等待的事务。
由于目标事务已经提交完毕了,因此这些剩余事务已经不需要再等待目标事务了,现在这些剩余事务应该等待被唤醒的该第一个事务,也即是说,计算设备将该事务的阻塞事务参数(blocking_trx)设置为该第一个事务的事务标识(即事务ID),换言之,另新添加到写锁等待队列(wait_que_write)的每个事务的阻塞事务参数(blocking_trx)均配置为被唤醒的该第一个事务的事务ID。
610-B、在该写锁等待队列的第一个事务申请的锁类型为读锁的情况下,计算设备唤醒该写锁等待队列中申请的锁类型为读锁的所有事务。
如果该写锁等待队列(wait_que_write)的第一个事务申请的锁类型是读锁,由于读锁是共享锁,因此能够一次性唤醒该写锁等待队列(wait_que_write)中所有请求读锁的事务,此时,计算设备遍历该写锁等待队列(wait_que_write),确定出申请的锁类型为读锁的所有事务,然后唤醒这些确定得到的事务。
在一些实施例中,为了维护全局读锁信息slock_table的正确性,还需要在该全局读锁信息slock_table中,将该写锁等待队列(wait_que_write)中申请的锁类型为读锁的所有事务添加至该数据记录的读锁持有队列(hold_que_read)。换言之,以当前遍历到的该数据记录的记录ID为索引,在全局读锁信息slock_table中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的读锁持有队列(hold_que_read),然后将该写锁等待队列(wait_que_write)中所有请求读锁的事务的事务ID都添加到该读锁持有队列(hold_que_read)中。
进一步的,由于一次性唤醒了该写锁等待队列(wait_que_write)中所有请求读锁的事务,此时该写锁等待队列(wait_que_write)中仅剩下了申请的锁类型为写锁的所有事务,这些事务已经不需要再等待目标事务(目标事务已提交),因此,需要将将该写锁等待队列(wait_que_write)中申请的锁类型为写锁的所有事务添加到全局读锁信息slock_table中该数据记录的读锁等待队列(wait_que_read)。换言之,由于上一操作中已经利用记录ID在全局读锁信息slock_table中查询到了对应的Key-Value数据结构,这一Key-Value数据结构的Value中存储了两个队列,一个是该数据记录的读锁持有队列(hold_que_read),一个是该数据记录的读锁等待队列(wait_que_read),上一操作中已经将该写锁等待队列(wait_que_write)中所有请求读锁的事务的事务ID都添加到该读锁持有队列(hold_que_read)中了,在本次只需要将该写锁等待队列(wait_que_write)中剩余的所有事务的事务ID一起挂载到该读锁等待队列(wait_que_read)中即可。
进一步的,针对上述挂载到该读锁等待队列(wait_que_read)中的每个事务,由于等待的事务已经从目标事务变成了被唤醒的持有读锁的事务,因此还需对新添加到该读锁等待队列(wait_que_read)中的任一事务,更新其阻塞事务参数(blocking_trx),其中该阻塞事务参数(blocking_trx)用于表征该事务所等待的事务。
由于目标事务已经提交完毕了,因此原本在等待目标事务的事务已经不需要再等待目标事务了,现在这些事务应该等待被唤醒的持有读锁的事务,也即是说,计算设备将该事务的阻塞事务参数(blocking_trx)设置为该读锁持有队列(hold_que_read)中除了该事务之外的第一个事务的事务标识(即事务ID)。换言之,另新添加到读锁等待队列(wait_que_read)的每个事务的阻塞事务参数(blocking_trx)均配置为对应的读锁持有队列(hold_que_read)中第一个不等于自己的事务的事务ID。
需要说明的是,由于在这种情况下全局读锁信息slock_table中,与本条数据记录对应的读锁持有队列(hold_que_read)和读锁等待队列(wait_que_read)都有元素了(从已提交的目标事务的写锁等待队列中,将申请读锁的所有事务挂载到读锁持有队列,将申请写锁的所有事务挂载到读锁等待队列),因此,这一数据记录的读锁不可能被其他事务的读锁抢占或者写锁抢占,因此不可能存在由于锁被抢占导致加锁不成功的情况。
上述所有可选技术方案,能够采用任意结合形成本公开的可选实施例,在此不再一一赘述。
本申请实施例提供的方法,通过在目标事务对数据记录申请写锁的情况下,利用全局读锁信息做读锁冲突检测,利用修改该数据记录的最新事务的事务状态做写锁冲突检测,并对该最新事务维护写锁等待信息以便于及时唤醒处于锁等待阶段的目标事务,使得整体系统的冲突检测无需依赖于锁管理器,也无需每次访问互斥量,能够加快锁申请的流程,并且,仅在冲突检测未通过即存在冲突的情况下,才申请创建相应的锁信息,针对不存在冲突的情况则无需耗费资源来维护锁信息,能够极大减少系统内创建不必要的行锁,从而节约锁机制下并发控制的存储开销和内存占用。
在上面两个实施例中,分别介绍了在目标事务申请读锁或申请写锁的情况下,对目标事务的冲突检测流程、目标事务的执行流程、执行后提交完毕的释放锁流程,这一事务锁方案能够适用于单机事务、分布式事务、读事务、写事务等各种类型的事务,本申请实施例不对目标事务的类型进行具体限定。
而在本申请实施例中,将针对如果目标事务在验证阶段未通过验证,致使目标事务被回滚的情况下,需要释放一定的锁信息,以取消事务等待,可选地,验证不通过的原因包括但不限于:陷入死锁、锁等待超时、应用程序崩溃、目标事务的执行进程或线程崩溃等。
在目标事务回滚后,首先,计算设备需要从目标事务所等待的第一事务的写锁等待队列中移除自己,表明目标事务已经不再等待该第一事务的写锁了(因为目标事务已经被回滚了),此时,计算设备基于该目标事务的阻塞事务参数(blocking_trx),确定该目标事务所等待的第一事务,该第一事务是指该目标事务的阻塞事务参数(blocking_trx)中当前记录的事务ID所指向的事务,然后,在内存中访问该第一事务的上下文信息中的哈希表字段(TRX_LOCK_WAIT),以访问该第一事务的写锁等待信息,接着,以该目标事务所涉及操作的每个数据记录的记录ID为索引,在该第一事务的写锁等待信息中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的写锁等待队列(wait_que_write),接着从该写锁等待队列(wait_que_write)中删除该目标事务的事务ID,由于目标事务可能操作多条数据记录,因此对每条数据记录都需要重复执行上述操作,以在该第一事务的写锁等待信息中,从该目标事务所操作的每条数据记录的写锁等待队列(wait_que_write)中,均删除该目标事务的事务ID。
其次,计算设备需要从全局读锁信息slock_table中,从该目标事务所操作的每条数据记录的读锁等待队列(wait_que_read)中移除自己,表明目标事务已经不再等待这个读锁了(因为目标事务已经被回滚了),此时,计算设备以目标事务所操作的每条数据记录的记录ID为索引,在全局读锁信息slock_table中查询该索引所命中的Key-Value数据结构,然后访问命中的该Key-Value数据结构的Value中存储的读锁等待队列(wait_que_read),接着从该读锁等待队列(wait_que_read)中删除该目标事务的事务ID,由于目标事务可能操作多条数据记录,因此对每条数据记录都需要重复执行上述操作,以在该全局读锁信息slock_table中,从该目标事务所操作的每条数据记录的读锁等待队列(wait_que_read)中,均删除该目标事务的事务ID。
接着,在从该目标事务所操作的每条数据记录的读锁等待队列(wait_que_read)中删除该目标事务的事务ID之后,还可以判断是否能够唤醒删除得到的读锁等待队列(wait_que_read)中的第一个等待事务,只有在该读锁等待队列(wait_que_read)中的第一个等待事务恰好是当前数据记录的读锁持有队列(hold_que_read)中的唯一的一个事务的情况下,才表明能够唤醒该第一个等待事务。
也即是说,计算设备在该全局读锁信息slock_table中,以当前该数据记录的记录标识(即记录ID)为索引,查询该数据记录的读锁持有队列(hold_que_read),查询方式上一实施例已经介绍过了这里不做赘述,然后判断该读锁持有队列(hold_que_read)是否仅包含单个元素,如果读锁持有队列(hold_que_read)仅包含单个元素,再判断该元素是否等于读锁等待队列(wait_que_read)中的第一个元素,如果满足读锁持有队列(hold_que_read)仅包含单个元素且该元素等于读锁等待队列(wait_que_read)中的第一个元素,说明可以唤醒该元素所对应的事务,换言之,在该读锁持有队列(hold_que_read)仅包含单个事务,且该事务恰好是该读锁等待队列(wait_que_read)中的第一个事务的情况下,唤醒该事务。
否则,如果不满足上述条件,比如,读锁持有队列(hold_que_read)包括两个或两个以上元素,或者,读锁持有队列(hold_que_read)包含的单个元素不等于读锁等待队列(wait_que_read)中的第一个元素,那么不能唤醒任何事务。需要说明的是,此时不需要判断是否需要唤醒被回滚的目标事务的写锁等待队列(wait_que_write)中的事务,因此目标事务自身处于锁等待阶段的情况下,其写锁等待队列(wait_que_write)一定会被整个挂载到目标事务所等待的第一事务的写锁等待信息中,因此目标事务自身的写锁等待队列(wait_que_write)中不会有等待的事务。
上述各个实施例中提供了完备的事务锁方案,能够适应于任何高并发场景下,缓解传统InnoDB引擎中全局的锁管理器的互斥量成为性能主要瓶颈的情况,由于极大缩短了锁的存储开销,且降低了创建的锁数量,能够极大提升事务处理性能,此外,针对较低冲突但涉及修改较大数据量的事务负载,此时能够在保证不损失并发性能的前提条件下,仅创建少量的锁信息来实现并发控制,从而极大节约了服务器的内存占用,优化了资源利用率。
图7是本申请实施例提供的一种事务处理装置的结构示意图,请参考图7,该装置包括:
确定模块701,用于基于目标事务所操作的数据记录,确定修改该数据记录的最新事务;
冲突检测模块702,用于基于全局读锁信息和该最新事务的写锁等待信息,对该目标事务进行锁申请的冲突检测,该全局读锁信息用于管理数据库系统中的读锁,该写锁等待信息用于记录等待该最新事务所持有写锁的各个事务;
锁申请模块703,用于在该冲突检测指示存在冲突的情况下,申请对该数据记录添加与该操作的操作类型对应的锁。
本申请实施例提供的装置,通过全局读锁信息记录数据库系统中的读锁的相关信息,通过修改每条数据记录的最新事务能够确定在该数据记录上是否存在写锁以及写锁的锁持有者,并且将写锁等待信息打散存储到每个事务的上下文信息中,使得整个数据库系统的读写冲突检测无需依赖于锁管理器,也无需每次访问互斥量,利用全局读锁信息和所欲操作的数据记录所对应最新事务的写锁等待信息完成冲突检测后,能够仅针对存在冲突的情况,才申请创建相应的锁信息,针对不存在冲突的情况则无需耗费资源来维护锁信息,能够极大减少系统内创建不必要的行锁,从而节约锁机制下并发控制的存储开销和内存占用。
在一种可能实施方式中,基于图7的装置组成,该冲突检测模块702包括:
确定单元,用于基于该操作类型,确定该目标事务待申请的锁类型;
第一冲突检测单元,用于在该锁类型为读锁的情况下,仅对该目标事务进行写锁冲突检测;
第二冲突检测单元,用于在该锁类型为写锁的情况下,对该目标事务进行读锁冲突检测和写锁冲突检测。
在一种可能实施方式中,基于图7的装置组成,该第一冲突检测单元包括:
获取子单元,用于在该锁类型为读锁的情况下,获取该最新事务的事务状态;
确定子单元,用于在该事务状态不是活跃状态的情况下,将冲突检测结果确定为不存在冲突;
该确定子单元,还用于在该事务状态是活跃状态的情况下,将该冲突检测结果确定为存在冲突。
在一种可能实施方式中,在该事务状态不是活跃状态的情况下,基于图7的装置组成,该第一冲突检测单元还包括:
查询子单元,用于在该全局读锁信息中,以该数据记录的记录标识为索引,查询该数据记录的读锁持有队列,该读锁持有队列用于记录持有该数据记录的读锁的各个事务;
添加子单元,用于在该读锁持有队列中不包含该目标事务的情况下,将该目标事务添加至该读锁持有队列。
在一种可能实施方式中,该最新事务的写锁等待信息包括该最新事务所操作的每条数据记录的写锁等待队列,该写锁等待队列用于记录等待该最新事务对该数据记录所持有写锁的各个事务;
在该事务状态是活跃状态的情况下,基于图7的装置组成,该第一冲突检测单元还包括:
添加子单元,用于在该最新事务的写锁等待信息中,将该目标事务添加至该数据记录的写锁等待队列;
设置子单元,用于将该目标事务的阻塞事务参数设置为该最新事务的事务标识,该阻塞事务参数用于表征该目标事务所等待的事务。
在一种可能实施方式中,基于图7的装置组成,该第二冲突检测单元包括:
读锁冲突检测子单元,用于在该锁类型为写锁的情况下,对该目标事务进行读锁冲突检测;
确定子单元,用于在该读锁冲突检测指示存在读锁冲突的情况下,将冲突检测结果确定为存在冲突;
写锁冲突检测子单元,用于在该读锁冲突检测指示不存在读锁冲突的情况下,对该目标事务进行写锁冲突检测;
该确定子单元,还用于若该写锁冲突检测指示存在写锁冲突,则将该冲突检测结果确定为存在冲突;若该写锁冲突检测指示不存在写锁冲突,则将该冲突检测结果确定为不存在冲突。
在一种可能实施方式中,该读锁冲突检测子单元用于:
在该全局读锁信息中,以该数据记录的记录标识为索引,查询该数据记录的读锁持有队列,该读锁持有队列用于记录持有该数据记录的读锁的各个事务;
在该读锁持有队列为空的情况下,返回不存在读锁冲突;
在该读锁持有队列仅包含该目标事务的情况下,查询该数据记录的读锁等待队列,该读锁等待队列用于记录等待对该数据记录所持有读锁的各个事务;在该读锁等待队列为空的情况下,返回不存在读锁冲突;在该读锁等待队列不为空的情况下,返回存在读锁冲突;
在该读锁持有队列包含除了该目标事务之外的事务的情况下,返回存在读锁冲突。
在一种可能实施方式中,在该读锁持有队列仅包含该目标事务且该读锁等待队列不为空,或者,该读锁持有队列包含除了该目标事务之外的事务的情况下,基于图7的装置组成,该第二冲突检测单元还包括:
添加子单元,用于将该目标事务添加至该读锁等待队列;
该添加子单元,还用于基于该目标事务的写锁等待信息,确定等待该目标事务对该数据记录所申请写锁的各个事务;将该等待该目标事务对该数据记录所申请写锁的各个事务添加到该读锁等待队列。
在一种可能实施方式中,基于图7的装置组成,该第二冲突检测单元还包括:
设置子单元,用于对添加到该读锁等待队列中的任一事务,将该事务的阻塞事务参数设置为该读锁持有队列中除了该事务之外的第一个事务的事务标识,该阻塞事务参数用于表征该事务所等待的事务。
在一种可能实施方式中,该写锁冲突检测子单元用于:
获取该最新事务的事务状态;
在该事务状态不是活跃状态的情况下,返回不存在写锁冲突;
在该事务状态是活跃状态的情况下,返回存在写锁冲突。
在一种可能实施方式中,在该事务状态不是活跃状态的情况下,基于图7的装置组成,该第二冲突检测单元还包括:
写入子单元,用于在该数据记录的目标隐藏字段中,写入该目标事务的事务标识,其中,该目标隐藏字段用于记录修改该数据记录的最新事务的事务标识。
在一种可能实施方式中,该最新事务的写锁等待信息包括该最新事务所操作的每条数据记录的写锁等待队列,该写锁等待队列用于记录等待该最新事务对该数据记录所持有写锁的各个事务;
在该事务状态是活跃状态的情况下,基于图7的装置组成,该第二冲突检测单元还包括:
添加子单元,用于在该最新事务的写锁等待信息中,将该目标事务添加至该数据记录的写锁等待队列;
该添加子单元,还用于基于该目标事务的写锁等待信息,确定等待该目标事务对该数据记录所申请写锁的各个事务;在该最新事务的写锁等待信息中,将该等待该目标事务对该数据记录所申请写锁的各个事务添加到该数据记录的写锁等待队列。
在一种可能实施方式中,基于图7的装置组成,该第二冲突检测单元还包括:
设置子单元,用于对添加到该写锁等待队列中的任一事务,将该事务的阻塞事务参数设置为该最新事务的事务标识,该阻塞事务参数用于表征该事务所等待的事务。
在一种可能实施方式中,在该锁类型为读锁的情况下,基于图7的装置组成,该冲突检测模块702还包括:
查询单元,用于在该目标事务提交后,在该全局读锁信息中,以该数据记录的记录标识为索引,查询该数据记录的读锁持有队列,该读锁持有队列用于记录持有该数据记录的读锁的各个事务;
唤醒单元,用于在该读锁持有队列为空的情况下,唤醒该数据记录的读锁等待队列中的第一个事务,该读锁等待队列用于记录等待对该数据记录所持有读锁的各个事务;
该唤醒单元,还用于在该读锁持有队列仅包含单个事务,且该事务恰好是该读锁等待队列中的第一个事务的情况下,唤醒该事务;
设置单元,用于否则,对该读锁等待队列中的每个事务,将该事务的阻塞事务参数设置为该读锁持有队列中除了该事务之外的第一个事务的事务标识,该阻塞事务参数用于表征该事务所等待的事务。
在一种可能实施方式中,对于该目标事务提交后唤醒的事务,基于图7的装置组成,该冲突检测模块702还包括:
添加单元,用于在该唤醒的事务的写锁等待信息中,将该读锁等待队列中除了该唤醒的事务之外的各个事务添加至该数据记录的写锁等待队列;
该设置单元,还用于对添加到该写锁等待队列中的任一事务,将该事务的阻塞事务参数设置为该唤醒的事务的事务标识,该阻塞事务参数用于表征该事务所等待的事务。
在一种可能实施方式中,在该锁类型为写锁的情况下,基于图7的装置组成,该冲突检测模块702还包括:
遍历单元,用于在该目标事务提交后,遍历该目标事务的写锁等待信息中每条数据记录的写锁等待队列,该写锁等待队列用于记录等待该目标事务对该数据记录所持有写锁的各个事务;
唤醒单元,用于对任一数据记录的写锁等待队列,在该写锁等待队列的第一个事务申请的锁类型为写锁的情况下,唤醒该第一个事务;在该写锁等待队列的第一个事务申请的锁类型为读锁的情况下,唤醒该写锁等待队列中申请的锁类型为读锁的所有事务。
在一种可能实施方式中,对任一数据记录的写锁等待队列,在该写锁等待队列的第一个事务申请的锁类型为写锁的情况下,对于该第一个事务,基于图7的装置组成,该冲突检测模块702还包括:
添加单元,用于在该第一个事务的写锁等待信息中,将该写锁等待队列中除了该第一个事务之外的各个事务添加至该数据记录的写锁等待队列;
该设置单元,还用于对添加到该写锁等待队列中的任一事务,将该事务的阻塞事务参数设置为该第一个事务的事务标识,该阻塞事务参数用于表征该事务所等待的事务。
在一种可能实施方式中,对任一数据记录的写锁等待队列,在该写锁等待队列的第一个事务申请的锁类型为读锁的情况下,基于图7的装置组成,该冲突检测模块702还包括:
添加单元,用于在该全局读锁信息中,将该写锁等待队列中申请的锁类型为读锁的所有事务添加至该数据记录的读锁持有队列;
该添加单元,还用于将该写锁等待队列中申请的锁类型为写锁的所有事务添加到该数据记录的读锁等待队列。
在一种可能实施方式中,该设置单元还用于:
对添加到该读锁等待队列中的任一事务,将该事务的阻塞事务参数设置为该读锁持有队列中除了该事务之外的第一个事务的事务标识,该阻塞事务参数用于表征该事务所等待的事务。
在一种可能实施方式中,该确定模块701还用于:在该目标事务回滚后,基于该目标事务的阻塞事务参数,确定该目标事务所等待的第一事务;
基于图7的装置组成,该装置还包括:
删除模块,用于在该第一事务的写锁等待信息中,从该目标事务所操作的数据记录的写锁等待队列中删除该目标事务;
该删除模块,还用于在该全局读锁信息中,从该目标事务所操作的数据记录的读锁等待队列中删除该目标事务。
在一种可能实施方式中,基于图7的装置组成,该装置还包括:
查询模块,用于在该全局读锁信息中,以该数据记录的记录标识为索引,查询该数据记录的读锁持有队列,该读锁持有队列用于记录持有该数据记录的读锁的各个事务;
唤醒模块,用于在该读锁持有队列仅包含单个事务,且该事务恰好是该读锁等待队列中的第一个事务的情况下,唤醒该事务。
上述所有可选技术方案,能够采用任意结合形成本公开的可选实施例,在此不再一一赘述。
需要说明的是:上述实施例提供的事务处理装置在处理事务时,仅以上述各功能模块的划分进行举例说明,实际应用中,能够根据需要而将上述功能分配由不同的功能模块完成,即将计算机设备的内部结构划分成不同的功能模块,以完成以上描述的全部或者部分功能。另外,上述实施例提供的事务处理装置与事务处理方法实施例属于同一构思,其具体实现过程详见事务处理方法实施例,这里不再赘述。
图8是本申请实施例提供的一种计算机设备的结构示意图。可选地,该终端800的设备类型包括:智能手机、平板电脑、MP3播放器(Moving Picture Experts Group AudioLayer III,动态影像专家压缩标准音频层面3)、MP4(Moving Picture Experts GroupAudio Layer IV,动态影像专家压缩标准音频层面4)播放器、笔记本电脑或台式电脑。终端800还可能被称为用户设备、便携式终端、膝上型终端、台式终端等其他名称。
通常,终端800包括有:处理器801和存储器802。
可选地,处理器801包括一个或多个处理核心,比如4核心处理器、8核心处理器等。可选地,处理器801采用DSP(Digital Signal Processing,数字信号处理)、FPGA(Field-Programmable Gate Array,现场可编程门阵列)、PLA(Programmable Logic Array,可编程逻辑阵列)中的至少一种硬件形式来实现。在一些实施例中,处理器801包括主处理器和协处理器,主处理器是用于对在唤醒状态下的数据进行处理的处理器,也称CPU(CentralProcessing Unit,中央处理器);协处理器是用于对在待机状态下的数据进行处理的低功耗处理器。在一些实施例中,处理器801集成有GPU(Graphics Processing Unit,图像处理器),GPU用于负责显示屏所需要显示的内容的渲染和绘制。一些实施例中,处理器801还包括AI(Artificial Intelligence,人工智能)处理器,该AI处理器用于处理有关机器学习的计算操作。
在一些实施例中,存储器802包括一个或多个计算机可读存储介质,可选地,该计算机可读存储介质是非暂态的。可选地,存储器802还包括高速随机存取存储器,以及非易失性存储器,比如一个或多个磁盘存储设备、闪存存储设备。在一些实施例中,存储器802中的非暂态的计算机可读存储介质用于存储至少一个程序代码,该至少一个程序代码用于被处理器801所执行以实现本申请中各个实施例提供的事务处理方法。
在一些实施例中,终端800还可选包括有:外围设备接口803和至少一个外围设备。处理器801、存储器802和外围设备接口803之间能够通过总线或信号线相连。各个外围设备能够通过总线、信号线或电路板与外围设备接口803相连。具体地,外围设备包括:射频电路804、显示屏805、摄像头组件806、音频电路807和电源808中的至少一种。
外围设备接口803可被用于将I/O(Input/Output,输入/输出)相关的至少一个外围设备连接到处理器801和存储器802。在一些实施例中,处理器801、存储器802和外围设备接口803被集成在同一芯片或电路板上;在一些其他实施例中,处理器801、存储器802和外围设备接口803中的任意一个或两个在单独的芯片或电路板上实现,本实施例对此不加以限定。
射频电路804用于接收和发射RF(Radio Frequency,射频)信号,也称电磁信号。射频电路804通过电磁信号与通信网络以及其他通信设备进行通信。射频电路804将电信号转换为电磁信号进行发送,或者,将接收到的电磁信号转换为电信号。可选地,射频电路804包括:天线系统、RF收发器、一个或多个放大器、调谐器、振荡器、数字信号处理器、编解码芯片组、用户身份模块卡等等。可选地,射频电路804通过至少一种无线通信协议来与其它终端进行通信。该无线通信协议包括但不限于:城域网、各代移动通信网络(2G、3G、4G及5G)、无线局域网和/或WiFi(Wireless Fidelity,无线保真)网络。在一些实施例中,射频电路804还包括NFC(Near Field Communication,近距离无线通信)有关的电路,本申请对此不加以限定。
显示屏805用于显示UI(User Interface,用户界面)。可选地,该UI包括图形、文本、图标、视频及其它们的任意组合。当显示屏805是触摸显示屏时,显示屏805还具有采集在显示屏805的表面或表面上方的触摸信号的能力。该触摸信号能够作为控制信号输入至处理器801进行处理。可选地,显示屏805还用于提供虚拟按钮和/或虚拟键盘,也称软按钮和/或软键盘。在一些实施例中,显示屏805为一个,设置终端800的前面板;在另一些实施例中,显示屏805为至少两个,分别设置在终端800的不同表面或呈折叠设计;在再一些实施例中,显示屏805是柔性显示屏,设置在终端800的弯曲表面上或折叠面上。甚至,可选地,显示屏805设置成非矩形的不规则图形,也即异形屏。可选地,显示屏805采用LCD(LiquidCrystal Display,液晶显示屏)、OLED(Organic Light-Emitting Diode,有机发光二极管)等材质制备。
摄像头组件806用于采集图像或视频。可选地,摄像头组件806包括前置摄像头和后置摄像头。通常,前置摄像头设置在终端的前面板,后置摄像头设置在终端的背面。在一些实施例中,后置摄像头为至少两个,分别为主摄像头、景深摄像头、广角摄像头、长焦摄像头中的任意一种,以实现主摄像头和景深摄像头融合实现背景虚化功能、主摄像头和广角摄像头融合实现全景拍摄以及VR(Virtual Reality,虚拟现实)拍摄功能或者其它融合拍摄功能。在一些实施例中,摄像头组件806还包括闪光灯。可选地,闪光灯是单色温闪光灯,或者是双色温闪光灯。双色温闪光灯是指暖光闪光灯和冷光闪光灯的组合,用于不同色温下的光线补偿。
在一些实施例中,音频电路807包括麦克风和扬声器。麦克风用于采集用户及环境的声波,并将声波转换为电信号输入至处理器801进行处理,或者输入至射频电路804以实现语音通信。出于立体声采集或降噪的目的,麦克风为多个,分别设置在终端800的不同部位。可选地,麦克风是阵列麦克风或全向采集型麦克风。扬声器则用于将来自处理器801或射频电路804的电信号转换为声波。可选地,扬声器是传统的薄膜扬声器,或者是压电陶瓷扬声器。当扬声器是压电陶瓷扬声器时,不仅能够将电信号转换为人类可听见的声波,也能够将电信号转换为人类听不见的声波以进行测距等用途。在一些实施例中,音频电路807还包括耳机插孔。
电源808用于为终端800中的各个组件进行供电。可选地,电源808是交流电、直流电、一次性电池或可充电电池。当电源808包括可充电电池时,该可充电电池支持有线充电或无线充电。该可充电电池还用于支持快充技术。
在一些实施例中,终端800还包括有一个或多个传感器810。该一个或多个传感器810包括但不限于:加速度传感器811、陀螺仪传感器812、压力传感器813、光学传感器814以及接近传感器815。
在一些实施例中,加速度传感器811检测以终端800建立的坐标系的三个坐标轴上的加速度大小。比如,加速度传感器811用于检测重力加速度在三个坐标轴上的分量。可选地,处理器801根据加速度传感器811采集的重力加速度信号,控制显示屏805以横向视图或纵向视图进行用户界面的显示。加速度传感器811还用于游戏或者用户的运动数据的采集。
在一些实施例中,陀螺仪传感器812检测终端800的机体方向及转动角度,陀螺仪传感器812与加速度传感器811协同采集用户对终端800的3D动作。处理器801根据陀螺仪传感器812采集的数据,实现如下功能:动作感应(比如根据用户的倾斜操作来改变UI)、拍摄时的图像稳定、游戏控制以及惯性导航。
可选地,压力传感器813设置在终端800的侧边框和/或显示屏805的下层。当压力传感器813设置在终端800的侧边框时,能够检测用户对终端800的握持信号,由处理器801根据压力传感器813采集的握持信号进行左右手识别或快捷操作。当压力传感器813设置在显示屏805的下层时,由处理器801根据用户对显示屏805的压力操作,实现对UI界面上的可操作性控件进行控制。可操作性控件包括按钮控件、滚动条控件、图标控件、菜单控件中的至少一种。
光学传感器814用于采集环境光强度。在一个实施例中,处理器801根据光学传感器814采集的环境光强度,控制显示屏805的显示亮度。具体地,当环境光强度较高时,调高显示屏805的显示亮度;当环境光强度较低时,调低显示屏805的显示亮度。在另一个实施例中,处理器801还根据光学传感器814采集的环境光强度,动态调整摄像头组件806的拍摄参数。
接近传感器815,也称距离传感器,通常设置在终端800的前面板。接近传感器815用于采集用户与终端800的正面之间的距离。在一个实施例中,当接近传感器815检测到用户与终端800的正面之间的距离逐渐变小时,由处理器801控制显示屏805从亮屏状态切换为息屏状态;当接近传感器815检测到用户与终端800的正面之间的距离逐渐变大时,由处理器801控制显示屏805从息屏状态切换为亮屏状态。
本领域技术人员能够理解,图8中示出的结构并不构成对终端800的限定,能够包括比图示更多或更少的组件,或者组合某些组件,或者采用不同的组件布置。
图9是本申请实施例提供的一种计算机设备的结构示意图,该计算机设备900可因配置或性能不同而产生比较大的差异,该计算机设备900包括一个或一个以上处理器(Central Processing Units,CPU)901和一个或一个以上的存储器902,其中,该存储器902中存储有至少一条计算机程序,该至少一条计算机程序由该一个或一个以上处理器901加载并执行以实现上述各个实施例提供的事务处理方法。可选地,该计算机设备900还具有有线或无线网络接口、键盘以及输入输出接口等部件,以便进行输入输出,该计算机设备900还包括其他用于实现设备功能的部件,在此不做赘述。
在示例性实施例中,还提供了一种计算机可读存储介质,例如包括至少一条计算机程序的存储器,上述至少一条计算机程序可由终端中的处理器执行以完成上述各个实施例中的事务处理方法。例如,该计算机可读存储介质包括ROM(Read-Only Memory,只读存储器)、RAM(Random-Access Memory,随机存取存储器)、CD-ROM(Compact Disc Read-OnlyMemory,只读光盘)、磁带、软盘和光数据存储设备等。
在示例性实施例中,还提供了一种计算机程序产品或计算机程序,包括一条或多条程序代码,该一条或多条程序代码存储在计算机可读存储介质中。计算机设备的一个或多个处理器能够从计算机可读存储介质中读取该一条或多条程序代码,该一个或多个处理器执行该一条或多条程序代码,使得计算机设备能够执行以完成上述实施例中的事务处理方法。
本领域普通技术人员能够理解实现上述实施例的全部或部分步骤能够通过硬件来完成,也能够通过程序来指令相关的硬件完成,可选地,该程序存储于一种计算机可读存储介质中,可选地,上述提到的存储介质是只读存储器、磁盘或光盘等。
以上所述仅为本申请的可选实施例,并不用以限制本申请,凡在本申请的精神和原则之内,所作的任何修改、等同替换、改进等,均应包含在本申请的保护范围之内。

Claims (20)

1.一种事务处理方法,其特征在于,所述方法包括:
基于目标事务所操作的数据记录,确定修改所述数据记录的最新事务;
基于全局读锁信息和所述最新事务的写锁等待信息,对所述目标事务进行锁申请的冲突检测,所述全局读锁信息用于管理数据库系统中的读锁,所述写锁等待信息用于记录等待所述最新事务所持有写锁的各个事务;
在所述冲突检测指示存在冲突的情况下,申请对所述数据记录添加与所述操作的操作类型对应的锁。
2.根据权利要求1所述的方法,其特征在于,所述基于全局读锁信息和所述最新事务的写锁等待信息,对所述目标事务进行锁申请的冲突检测包括:
基于所述操作类型,确定所述目标事务待申请的锁类型;
在所述锁类型为读锁的情况下,仅对所述目标事务进行写锁冲突检测;
在所述锁类型为写锁的情况下,对所述目标事务进行读锁冲突检测和写锁冲突检测。
3.根据权利要求2所述的方法,其特征在于,所述在所述锁类型为读锁的情况下,仅对所述目标事务进行写锁冲突检测包括:
在所述锁类型为读锁的情况下,获取所述最新事务的事务状态;
在所述事务状态不是活跃状态的情况下,将冲突检测结果确定为不存在冲突;
在所述事务状态是活跃状态的情况下,将所述冲突检测结果确定为存在冲突。
4.根据权利要求3所述的方法,其特征在于,在所述事务状态不是活跃状态的情况下,所述方法还包括:
在所述全局读锁信息中,以所述数据记录的记录标识为索引,查询所述数据记录的读锁持有队列,所述读锁持有队列用于记录持有所述数据记录的读锁的各个事务;
在所述读锁持有队列中不包含所述目标事务的情况下,将所述目标事务添加至所述读锁持有队列。
5.根据权利要求3所述的方法,其特征在于,所述最新事务的写锁等待信息包括所述最新事务所操作的每条数据记录的写锁等待队列,所述写锁等待队列用于记录等待所述最新事务对所述数据记录所持有写锁的各个事务;
在所述事务状态是活跃状态的情况下,所述方法还包括:
在所述最新事务的写锁等待信息中,将所述目标事务添加至所述数据记录的写锁等待队列;
将所述目标事务的阻塞事务参数设置为所述最新事务的事务标识,所述阻塞事务参数用于表征所述目标事务所等待的事务。
6.根据权利要求2所述的方法,其特征在于,所述在所述锁类型为写锁的情况下,对所述目标事务进行读锁冲突检测和写锁冲突检测包括:
在所述锁类型为写锁的情况下,对所述目标事务进行读锁冲突检测;
在所述读锁冲突检测指示存在读锁冲突的情况下,将冲突检测结果确定为存在冲突;
在所述读锁冲突检测指示不存在读锁冲突的情况下,对所述目标事务进行写锁冲突检测;若所述写锁冲突检测指示存在写锁冲突,则将所述冲突检测结果确定为存在冲突;若所述写锁冲突检测指示不存在写锁冲突,则将所述冲突检测结果确定为不存在冲突。
7.根据权利要求6所述的方法,其特征在于,所述对所述目标事务进行读锁冲突检测包括:
在所述全局读锁信息中,以所述数据记录的记录标识为索引,查询所述数据记录的读锁持有队列,所述读锁持有队列用于记录持有所述数据记录的读锁的各个事务;
在所述读锁持有队列为空的情况下,返回不存在读锁冲突;
在所述读锁持有队列仅包含所述目标事务的情况下,查询所述数据记录的读锁等待队列,所述读锁等待队列用于记录等待对所述数据记录所持有读锁的各个事务;在所述读锁等待队列为空的情况下,返回不存在读锁冲突;在所述读锁等待队列不为空的情况下,返回存在读锁冲突;
在所述读锁持有队列包含除了所述目标事务之外的事务的情况下,返回存在读锁冲突。
8.根据权利要求7所述的方法,其特征在于,在所述读锁持有队列仅包含所述目标事务且所述读锁等待队列不为空,或者,所述读锁持有队列包含除了所述目标事务之外的事务的情况下,所述方法还包括:
将所述目标事务添加至所述读锁等待队列;
基于所述目标事务的写锁等待信息,确定等待所述目标事务对所述数据记录所申请写锁的各个事务;
将所述等待所述目标事务对所述数据记录所申请写锁的各个事务添加到所述读锁等待队列;
对添加到所述读锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述读锁持有队列中除了所述事务之外的第一个事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
9.根据权利要求6所述的方法,其特征在于,所述对所述目标事务进行写锁冲突检测包括:
获取所述最新事务的事务状态;
在所述事务状态不是活跃状态的情况下,返回不存在写锁冲突;
在所述事务状态是活跃状态的情况下,返回存在写锁冲突。
10.根据权利要求9所述的方法,其特征在于,在所述事务状态不是活跃状态的情况下,所述方法还包括:
在所述数据记录的目标隐藏字段中,写入所述目标事务的事务标识,其中,所述目标隐藏字段用于记录修改所述数据记录的最新事务的事务标识。
11.根据权利要求9所述的方法,其特征在于,所述最新事务的写锁等待信息包括所述最新事务所操作的每条数据记录的写锁等待队列,所述写锁等待队列用于记录等待所述最新事务对所述数据记录所持有写锁的各个事务;
在所述事务状态是活跃状态的情况下,所述方法还包括:
在所述最新事务的写锁等待信息中,将所述目标事务添加至所述数据记录的写锁等待队列;
基于所述目标事务的写锁等待信息,确定等待所述目标事务对所述数据记录所申请写锁的各个事务;
在所述最新事务的写锁等待信息中,将所述等待所述目标事务对所述数据记录所申请写锁的各个事务添加到所述数据记录的写锁等待队列;
对添加到所述写锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述最新事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
12.根据权利要求2所述的方法,其特征在于,在所述锁类型为读锁的情况下,所述方法还包括:
在所述目标事务提交后,在所述全局读锁信息中,以所述数据记录的记录标识为索引,查询所述数据记录的读锁持有队列,所述读锁持有队列用于记录持有所述数据记录的读锁的各个事务;
在所述读锁持有队列为空的情况下,唤醒所述数据记录的读锁等待队列中的第一个事务,所述读锁等待队列用于记录等待对所述数据记录所持有读锁的各个事务;
在所述读锁持有队列仅包含单个事务,且所述事务恰好是所述读锁等待队列中的第一个事务的情况下,唤醒所述事务;
否则,对所述读锁等待队列中的每个事务,将所述事务的阻塞事务参数设置为所述读锁持有队列中除了所述事务之外的第一个事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
13.根据权利要求12所述的方法,其特征在于,对于所述目标事务提交后唤醒的事务,所述方法还包括:
在所述唤醒的事务的写锁等待信息中,将所述读锁等待队列中除了所述唤醒的事务之外的各个事务添加至所述数据记录的写锁等待队列;
对添加到所述写锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述唤醒的事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
14.根据权利要求2所述的方法,其特征在于,在所述锁类型为写锁的情况下,所述方法还包括:
在所述目标事务提交后,遍历所述目标事务的写锁等待信息中每条数据记录的写锁等待队列,所述写锁等待队列用于记录等待所述目标事务对所述数据记录所持有写锁的各个事务;
对任一数据记录的写锁等待队列,在所述写锁等待队列的第一个事务申请的锁类型为写锁的情况下,唤醒所述第一个事务;在所述写锁等待队列的第一个事务申请的锁类型为读锁的情况下,唤醒所述写锁等待队列中申请的锁类型为读锁的所有事务。
15.根据权利要求14所述的方法,其特征在于,对任一数据记录的写锁等待队列,在所述写锁等待队列的第一个事务申请的锁类型为写锁的情况下,对于所述第一个事务,所述方法还包括:
在所述第一个事务的写锁等待信息中,将所述写锁等待队列中除了所述第一个事务之外的各个事务添加至所述数据记录的写锁等待队列;
对添加到所述写锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述第一个事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
16.根据权利要求14所述的方法,其特征在于,对任一数据记录的写锁等待队列,在所述写锁等待队列的第一个事务申请的锁类型为读锁的情况下,所述方法还包括:
在所述全局读锁信息中,将所述写锁等待队列中申请的锁类型为读锁的所有事务添加至所述数据记录的读锁持有队列;
将所述写锁等待队列中申请的锁类型为写锁的所有事务添加到所述数据记录的读锁等待队列;
对添加到所述读锁等待队列中的任一事务,将所述事务的阻塞事务参数设置为所述读锁持有队列中除了所述事务之外的第一个事务的事务标识,所述阻塞事务参数用于表征所述事务所等待的事务。
17.根据权利要求1所述的方法,其特征在于,所述方法还包括:
在所述目标事务回滚后,基于所述目标事务的阻塞事务参数,确定所述目标事务所等待的第一事务;
在所述第一事务的写锁等待信息中,从所述目标事务所操作的数据记录的写锁等待队列中删除所述目标事务;
在所述全局读锁信息中,从所述目标事务所操作的数据记录的读锁等待队列中删除所述目标事务;
在所述全局读锁信息中,以所述数据记录的记录标识为索引,查询所述数据记录的读锁持有队列,所述读锁持有队列用于记录持有所述数据记录的读锁的各个事务;
在所述读锁持有队列仅包含单个事务,且所述事务恰好是所述读锁等待队列中的第一个事务的情况下,唤醒所述事务。
18.一种事务处理装置,其特征在于,所述装置包括:
确定模块,用于基于目标事务所操作的数据记录,确定修改所述数据记录的最新事务;
冲突检测模块,用于基于全局读锁信息和所述最新事务的写锁等待信息,对所述目标事务进行锁申请的冲突检测,所述全局读锁信息用于管理数据库系统中的读锁,所述写锁等待信息用于记录等待所述最新事务所持有写锁的各个事务;
锁申请模块,用于在所述冲突检测指示存在冲突的情况下,申请对所述数据记录添加与所述操作的操作类型对应的锁。
19.一种计算机设备,其特征在于,所述计算机设备包括一个或多个处理器和一个或多个存储器,所述一个或多个存储器中存储有至少一条计算机程序,所述至少一条计算机程序由所述一个或多个处理器加载并执行以实现如权利要求1至权利要求17任一项所述的事务处理方法。
20.一种存储介质,其特征在于,所述存储介质中存储有至少一条计算机程序,所述至少一条计算机程序由处理器加载并执行以实现如权利要求1至权利要求17任一项所述的事务处理方法。
CN202210106276.2A 2022-01-28 2022-01-28 事务处理方法、装置、计算机设备及存储介质 Pending CN116561137A (zh)

Priority Applications (1)

Application Number Priority Date Filing Date Title
CN202210106276.2A CN116561137A (zh) 2022-01-28 2022-01-28 事务处理方法、装置、计算机设备及存储介质

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
CN202210106276.2A CN116561137A (zh) 2022-01-28 2022-01-28 事务处理方法、装置、计算机设备及存储介质

Publications (1)

Publication Number Publication Date
CN116561137A true CN116561137A (zh) 2023-08-08

Family

ID=87495262

Family Applications (1)

Application Number Title Priority Date Filing Date
CN202210106276.2A Pending CN116561137A (zh) 2022-01-28 2022-01-28 事务处理方法、装置、计算机设备及存储介质

Country Status (1)

Country Link
CN (1) CN116561137A (zh)

Cited By (2)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN117076146A (zh) * 2023-10-16 2023-11-17 腾讯科技(深圳)有限公司 数据处理方法、装置、计算机设备和存储介质
CN117151712A (zh) * 2023-10-26 2023-12-01 腾讯科技(深圳)有限公司 区块链交易处理方法、装置、计算机设备和存储介质

Cited By (4)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN117076146A (zh) * 2023-10-16 2023-11-17 腾讯科技(深圳)有限公司 数据处理方法、装置、计算机设备和存储介质
CN117076146B (zh) * 2023-10-16 2024-01-30 腾讯科技(深圳)有限公司 数据处理方法、装置、计算机设备和存储介质
CN117151712A (zh) * 2023-10-26 2023-12-01 腾讯科技(深圳)有限公司 区块链交易处理方法、装置、计算机设备和存储介质
CN117151712B (zh) * 2023-10-26 2024-03-26 腾讯科技(深圳)有限公司 区块链交易处理方法、装置、计算机设备和存储介质

Similar Documents

Publication Publication Date Title
CN112463311B (zh) 事务处理方法、装置、计算机设备及存储介质
CN112035410B (zh) 日志存储方法、装置、节点设备及存储介质
CN114244595B (zh) 权限信息的获取方法、装置、计算机设备及存储介质
CN111338766A (zh) 事务处理方法、装置、计算机设备及存储介质
US20220164355A1 (en) Methods for updating reference count and shared objects in a concurrent system
US10970311B2 (en) Scalable snapshot isolation on non-transactional NoSQL
EP3513317A1 (en) Data serialization in a distributed event processing system
CN115114344B (zh) 事务处理方法、装置、计算设备及存储介质
CN116561137A (zh) 事务处理方法、装置、计算机设备及存储介质
US10176205B2 (en) Using parallel insert sub-ranges to insert into a column store
CN111444274A (zh) 数据同步方法、数据同步系统及其装置、介质和系统
WO2023284473A1 (zh) 数据管理方法、装置、计算机设备及存储介质
WO2020088681A1 (zh) 模型文件的管理方法和终端设备
CN115098537B (zh) 事务执行方法、装置、计算设备及存储介质
CN112162843A (zh) 工作流执行方法、装置、设备及存储介质
JP2015511749A (ja) ローカル・データーおよびリモート・データーの同期
WO2024098858A1 (zh) 数据库访问系统、方法、计算机设备和存储介质
WO2022048358A1 (zh) 数据处理方法、装置及存储介质
US10620660B2 (en) Efficient timestamp solution for analyzing concurrent software systems
CN113704361B (zh) 事务执行方法、装置、计算设备及存储介质
CN110995842A (zh) 业务数据下载方法、装置、设备及存储介质
CN107391539A (zh) 事务处理方法、服务器和存储介质
US10127270B1 (en) Transaction processing using a key-value store
CN115113989B (zh) 事务执行方法、装置、计算设备及存储介质
CN115114311A (zh) 一种事务执行方法以及相关装置

Legal Events

Date Code Title Description
PB01 Publication
PB01 Publication
SE01 Entry into force of request for substantive examination
SE01 Entry into force of request for substantive examination