优化MySQL悲观锁的锁等待超时时间的方法及装置与流程

文档序号:12963580阅读:618来源:国知局
优化MySQL悲观锁的锁等待超时时间的方法及装置与流程

本申请涉及mysql(mystructuredquerylanguage)数据库技术领域,尤其是涉及一种优化mysql悲观锁的锁等待超时时间的方法及装置。



背景技术:

对于一些系统而言,绝对不允许同一时刻有两个不同的线程对数据库中的同一条记录进行修改,否则会因数据并发写入而带来数据覆盖问题。为了避免这种数据并发写入带来的数据覆盖问题,一般会考虑给当前需要更新的数据加锁。

悲观锁作为数据库锁的一种,其具有强烈的排他性:如果事务成功获取到数据库锁,在整个事务执行过程中,数据将一直处于锁定状态,直到事务执行结束或者事务异常回滚才会释放悲观锁;而如果事务获取悲观锁失败,则会一直等待,直到超时。

与oracle数据库不同,mysql数据库在数据库层面并没有提供针对单个sql任务的悲观锁指定任意等待时间的实现,而只能设置全局性的锁等待超时时间。因此,在一些场景下,如果申请悲观锁失败,将会一直等待,直到数据库链接超时。比如,当前正在执行针对一个表的更新任务时,又收到了针对该表的查询任务,则针对该表的查询任务必须等到更新任务执行完毕并释放悲观锁后才能执行查询,因此,该查询任务就会一直等待获取悲观锁,直至超时(即超出全局性的锁等待超时时间)。这种方式在高并发场景下,将会导致大量的数据库连接被挂起(hold),进而可能导致数据库连接不足甚至雪崩。

为了解决上述获取悲观锁失败所带来的问题,我们可以将mysql数据库链接的超时时间设置短些,或者将mysql数据库的锁等待超时时间设置短些,但这些实现方式毕竟是一个全局的设置,其不能满足不同业务场景(特别是那些实时性要求高的业务场景)对锁等待超时时间的个性化需求。



技术实现要素:

本申请实施例的目的在于提供一种优化mysql悲观锁的锁等待超时时间的方法及装置,以实现可针对单个sql任务获取悲观锁时,指定任意锁等待超时时间,满足不同场景下对锁等待超时时间的个性化需求。

为达到上述目的,一方面本申请实施例提供了一种优化mysql悲观锁的锁等待超时时间的方法,包括以下步骤:

在业务代码被执行的过程中,拦截所述业务代码中的切入点,获取目标参数,所述目标参数中包括指定的锁等待超时时间;

解析所述目标参数,获取指定的锁等待超时时间,所述指定的锁等待超时时间小于或等于mysql数据库的全局锁等待超时时间;

执行与所述切入点对应的切面逻辑,以判断是否在所述锁等待超时时间内获取到悲观锁。

再一方面,本申请实施例还提供了一种优化mysql悲观锁的锁等待超时时间的装置,包括:

切入点拦截模块,用于在业务代码被执行的过程中,拦截所述业务代码中的切入点,获取目标参数,所述目标参数中包括指定的锁等待超时时间;

参数解析模块,用于解析所述目标参数,获取指定的锁等待超时时间,所述指定的锁等待超时时间小于或等于mysql数据库的全局锁等待超时时间;

切面执行模块,用于执行与所述切入点对应的切面逻辑,以判断是否在所述锁等待超时时间内获取到悲观锁。

本申请实施例中,在业务代码被执行的过程中,拦截业务代码中的切入点,获取获取其内包括指定的锁等待超时时间的目标参数;解析目标参数,获取指定的锁等待超时时间,指定的锁等待超时时间小于或等于mysql数据库的全局锁等待超时时间;执行与切入点对应的切面逻辑,以判断是否在锁等待超时时间内获取到悲观锁,从而实现了为单个sql任务任意指定mysql悲观锁的锁等待超时时间,满足了不同场景下对锁等待超时时间的个性化需求。此外,由于多个无论什么业务,实施时仅需要在指定的锁等待超时时间的代码块中预先通过注解的方式打上切入点,代码改造量仅仅需要一行,因此,本申请实施例是一种轻量级解决方案,可直接被多个业务系统复用。

附图说明

此处所说明的附图用来提供对本申请实施例的进一步理解,构成本申请实施例的一部分,并不构成对本申请实施例的限定。在附图中:

图1为本申请一实施例的优化mysql悲观锁的锁等待超时时间的方法的流程图;

图2为本申请一实施例的优化mysql悲观锁的锁等待超时时间的方法中局部步骤的流程图;

图3为本申请一实施例的优化mysql悲观锁的锁等待超时时间的装置的结构框图;

图4为本申请一实施例的优化mysql悲观锁的锁等待超时时间的装置中,切面执行模块的结构框图。

具体实施方式

为使本申请实施例的目的、技术方案和优点更加清楚明白,下面结合实施例和附图,对本申请实施例做进一步详细说明。在此,本申请实施例的示意性实施例及其说明用于解释本申请实施例,但并不作为对本申请实施例的限定。

下面结合附图,对本申请实施例的具体实施方式作进一步的详细说明。

在描述本申请实施例前需要声明,本申请以下实施例中所提到的悲观锁均是指mysql悲观锁,只是为了描述的方便,而简称为悲观锁。当然,本申请以下实施例中所提到锁等待超时时间也均是指等待获取mysql悲观锁的超时时间。

此外,本申请以下实施例用到springaop(aspectorientedprogramming,面向切面的编程)技术。其中,spring是一个轻量级的java开源框架。aop作为spring框架中的一个重要内容,其是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,当业务程序运行到需调用切入点所标识的方法部分时,转而跳转执行预设的切面逻辑,从而通过执行切面逻辑代为实现原有业务程序中切入点所标识的方法的调用。纵观springaop技术,其中需要程序员参与的一般有3个部分:

定义切入点(pointcut),切入点用于标识哪些业务组件需要被拦截;

定义需要拦截的业务组件;

定义切面逻辑(advice),切面逻辑就是在springaop框架内为业务组件中需要拦截的方法所织入的处理逻辑。

其中的关键就是定义切入点和定义切面逻辑,切面就是切入点和切面逻辑的集合,一旦定义了合适的切入点和切面逻辑,切面也就确定了,springaop框架将会自动生成aop代理。

参考图1所示,本申请实施例的优化mysql悲观锁的锁等待超时时间的方法包括以下步骤:

步骤s101、在业务代码被执行的过程中,拦截所述业务代码中的切入点,获取目标参数,所述目标参数中包括指定的锁等待超时时间。

本申请一实施例中,所述切入点包括预先通过注解方式定义的锁等待注解,且所述业务代码中指定的锁等待超时时间的代码块上标识有所述锁等待注解,对应的,所述目标参数包括锁等待注解参数。在本申请另一实施例中,所述切入点也可以通过其他方式定义,比如通过xml(extensiblemarkuplanguage,可扩展标记语言)配置的方式。

本申请实施例中,一般的,当在业务代码被执行到标识有切入点的位置,就会拦截到所述切入点。

本申请实施例中,所述业务代码中的切入点,可预先通过以下方式实现:

1)、定义锁等待注解,以作为切面的切入点。也就说本申请实施例中,可通过定义注解(annotation)的方式定义切入点。比如:@interfacelockwait。

2)、根据需要在业务代码中指定锁等待超时时间,并在该锁等待超时时间上标识所述锁等待注解,以用于切面对切入点(即锁等待注解)进行拦截。比如:

@lockwait(timeout=3)

publicinneraccountdolockaccount(stringaccountno)throwsdataaccessexception。

当然,在本申请实施例中,切面逻辑也是需要预先定义好的,至于本申请实施例的切面逻辑在下文中会有描述。

上述定义锁等待注解、指定锁等待超时时间、标识锁等待注解以及定义切面逻辑可以在预编译业务代码时进行。

步骤s102、解析所述目标参数,获取指定的锁等待超时时间,所述指定的锁等待超时时间小于或等于mysql数据库的全局锁等待超时时间。

本申请实施例中,所述目标参数包括锁等待注解参数,所述锁等待注解参数主要是时间参数,即预先指定的锁等待超时时间。比如:3秒,即认为3秒内如果没有获取到指定数据的悲观锁,则返回锁等待超时异常,等待业务重试处理;如果在3秒内获取悲观锁成功,则可以继续处理锁账号之后的业务。锁等待超时时间可以根据不同的业务场景在不同的sql语句环境进行动态调整(即通过注解参数的方式注入即可,不同的锁等待超时时间与不同的sql语句对应起来)。

在本申请一个实施例中,一般的,需要单独指定锁等待超时时间的sql语句的业务场景是:对实时性要求相对较高的业务场景,因为业务需求可能来不及等待mysql数据库的全局锁等待超时时间,比如mysql数据库的全局锁等待超时时间的为5秒,而某一sql语句获取悲观锁的等待时间要求是不超过3秒。因此,在这种场景下,需要让指定的锁等待超时时间小于或等于mysql数据库的全局锁等待超时时间。否则,指定的锁等待超时时间将不起作用。

步骤s103、执行与所述切入点对应的切面逻辑,以判断是否在所述锁等待超时时间内获取到悲观锁。

结合图2所示,步骤s103具体可以包括以下分步骤:

s1031、创建一个线程池;比如创建一个固定大小为1的线程池。

本分步骤中涉及到的线程池是一种预先创建线程的技术,在任务还没有到来之前,可利用线程池创建指定数量的线程,放入空闲队列中。这些线程都是处于睡眠状态,即均未启动,也不消耗cpu,而只是占用较小的内存空间。当任务到来之后,缓冲池给这次任务分配一个空闲线程,把任务传入此线程中以进行处理。利用线程池可以避免服务器频繁的创建对象及销毁对象所带的开销较大的问题(特别是在高并发任务场景下),因而利用线程池提高服务器效率。在本申请的一个具体实施例中,可以利用java.util.concurrent工具类中的executorservice类来实现线程池的创建。

s1032、将所述锁等待注解作为callable任务传递给所述线程池中的线程,获取future对象。

在本申请实施例中,callable是位于java.util.concurrent工具类中的实现callable接口的方法类call()(也可称为call函数)。所以,线程任务(即callable任务)实现callable接口后,对应call函数的实现即为执行连接点方法:

proceedingjoinpoint.process()。所述的连接点方法即为被代理的方法(即业务代码中被切入点所标注的方法)。

将所述锁等待注解作为callable任务传递给所述线程池中的线程就会得到一个future对象,通过future对象可以了解callable任务被线程池中的线程执行的情况。而future对象即为future所引用的对象,其中,future是位于java.util.concurrent工具类中的实现future接口的方法类。在future接口中声明了多个方法,本申请实施例中主要利用future接口中的get()方法(也可称为get函数)来获取callable任务的执行结果。

s1033、指定所述future对象获取悲观锁的超时时间为所述锁等待超时时间。

本分步骤实际上就是将步骤s102获取的锁等待超时时间在等待执行结果的时候生效。

s1034、使所述线程池中的线程执行所述callable任务,并判断所述future对象是否在所述锁等待超时时间内获取到悲观锁。

如果未在所述锁等待超时时间内获取到悲观锁,执行分步骤s1035;如果在所述锁等待超时时间内获取到悲观锁,执行分步骤s1036。

s1035、抛出锁等待超时异常,并释放数据库连接。

如果在所述锁等待超时时间内,所述future对象未获取到悲观锁,则会抛出超时异常,这个时候future对象会将超时异常封装为一个锁等待超时异常向外抛出,并释放数据库连接,以待后续重试。其中,在释放数据库连接之前,还可以对当前业务进行回滚,以将当前业务返回到上一次正确状态。spring业务的实现只会感知运行时异常runtimeexception和内部错误error,只有感知到这两种错误场景才会主动的进行业务回滚。所以,需要将线程异常进行封装。

s1036、获取悲观锁成功,并返回锁记录。

如果在所述锁等待超时时间内,所述future对象获取到了悲观锁,这则说明获取悲观锁成功,正常返回锁记录,其中,所谓的锁记录即为数据锁定记录。

上述步骤s1031-s1036仅是举例说明本申请实施例如何执行与所述切入点对应的切面逻辑,以判断是否在所述锁等待超时时间内获取到悲观锁的,而不应构成对本申请的限制。在本申请其他实施例中,也可以采用其他的切面逻辑,以判断是否在所述锁等待超时时间内获取到悲观锁。

本申请实施例中,在业务代码被执行的过程中,拦截业务代码中的切入点,获取锁等待注解参数,其中,切入点为锁等待注解,业务代码中指定的锁等待超时时间的代码块上标识有该锁等待注解;解析锁等待注解参数,获取指定的锁等待超时时间,指定的锁等待超时时间小于或等于mysql数据库的全局锁等待超时时间;执行与切入点对应的切面逻辑,以判断是否在锁等待超时时间内获取到悲观锁,从而实现了为单个sql任务任意指定mysql悲观锁的锁等待超时时间,满足了不同场景下对锁等待超时时间的个性化需求。此外,由于多个无论什么业务,实施时仅需要在指定的锁等待超时时间的代码块中预先通过注解的方式打上切入点,代码改造量仅仅需要一行,因此,本申请实施例是一种轻量级解决方案,可直接被多个业务系统复用。

虽然上文描述的过程流程包括以特定顺序出现的多个操作,但是,应当清楚了解,这些过程可以包括更多或更少的操作,这些操作可以顺序执行或并行执行(例如使用并行处理器或多线程环境)。

参考图3所示,本申请实施例的优化mysql悲观锁的锁等待超时时间的装置包括:

切入点拦截模块31,用于在业务代码被执行的过程中,拦截所述业务代码中的切入点,获取目标参数,所述目标参数中包括指定的锁等待超时时间。

本申请实施例中,一般的,当在业务代码被执行到标识有切入点的位置,就会拦截到所述切入点。

本申请一实施例中,所述切入点包括预先通过注解方式定义的锁等待注解,且所述业务代码中指定的锁等待超时时间的代码块上标识有所述锁等待注解,对应的,所述目标参数包括锁等待注解参数。在本申请另一实施例中,所述切入点也可以通过其他方式定义,比如通过xml配置的方式。

当然,在本申请实施例中,切面逻辑也是需要预先定义好的,至于本申请实施例的切面逻辑在下文中会有描述。

上述定义锁等待注解、指定锁等待超时时间、标识锁等待注解以及定义切面逻辑可以在预编译业务代码时进行。

参数解析模块32,用于解析所述目标参数,获取指定的锁等待超时时间,所述指定的锁等待超时时间小于或等于mysql数据库的全局锁等待超时时间。

本申请实施例中,所述目标参数包括锁等待注解参数,所述锁等待注解参数主要是时间参数,即预先指定的锁等待超时时间。比如:3秒,即认为3秒内如果没有获取到指定数据的悲观锁,则返回锁等待超时异常,等待业务重试处理;如果在3秒内获取悲观锁成功,则可以继续处理锁账号之后的业务。锁等待超时时间可以根据不同的业务场景在不同的sql语句环境进行动态调整(即通过注解参数的方式注入即可,不同的锁等待超时时间与不同的sql语句对应起来)。

在本申请一个实施例中,一般的,需要单独指定锁等待超时时间的sql语句的业务场景是:对实时性要求相对较高的业务场景,因为业务需求可能来不及等待mysql数据库的全局锁等待超时时间,比如mysql数据库的全局锁等待超时时间的为5秒,而某一sql语句获取悲观锁的等待时间要求是不超过3秒。因此,在这种场景下,需要让指定的锁等待超时时间小于或等于mysql数据库的全局锁等待超时时间。否则,指定的锁等待超时时间将不起作用。

切面执行模块33,用于执行与所述切入点对应的切面逻辑,以判断是否在所述锁等待超时时间内获取到悲观锁。

结合图4所示,所述切面执行模块33包括:

线程池创建子模块331,用于创建一个线程池。比如创建一个固定大小为1的线程池。

本子模块中涉及到的线程池是一种预先创建线程的技术,在任务还没有到来之前,可利用线程池创建指定数量的线程,放入空闲队列中。这些线程都是处于睡眠状态,即均未启动,也不消耗cpu,而只是占用较小的内存空间。当任务到来之后,缓冲池给这次任务分配一个空闲线程,把任务传入此线程中以进行处理。利用线程池可以避免服务器频繁的创建对象及销毁对象所带的开销较大的问题(特别是在高并发任务场景下),因而利用线程池提高服务器效率。在本申请的一个具体实施例中,可以利用java.util.concurrent工具类中的executorservice类来实现线程池的创建。

future对象获取子模块332,用于将所述锁等待注解作为callable任务传递给所述线程池中的线程,获取future对象。

超时时间指定子模块333,用于指定所述future对象获取悲观锁的超时时间为所述锁等待超时时间。

在本申请实施例中,callable是位于java.util.concurrent工具类中的实现callable接口的方法类call()(也可称为call函数)。所以,线程任务(即callable任务)实现callable接口后,对应call函数的实现即为执行连接点方法:proceedingjoinpoint.process()。所述的连接点方法即为被代理的方法(即业务代码中被切入点所标注的方法)。

将所述锁等待注解作为callable任务传递给所述线程池中的线程就会得到一个future对象,通过future对象可以了解callable任务被线程池中的线程执行的情况。而future对象即为future所引用的对象,而future是位于java.util.concurrent工具类中的实现future接口的方法类。在future接口中声明了多个方法,本申请实施例中主要利用future接口中的get()方法(也可称为get函数)来获取callable任务的执行结果。

超时判断子模块334,用于使所述线程池中的线程执行所述callable任务,并判断所述future对象是否在所述锁等待超时时间内获取到悲观锁。

第一处理子模块335,用于当所述超时判断子模块333判断未在所述锁等待超时时间内获取到悲观锁时,抛出锁等待超时异常,并释放数据库连接。此外,所述第一处理子模块334还可以用于在释放数据库连接之前,进行业务回滚,以将当前业务返回到上一次正确状态。

如果在所述锁等待超时时间内,所述future对象未获取到悲观锁,则会抛出超时异常,这个时候future对象会将超时异常封装为一个锁等待超时异常向外抛出,并释放数据库连接,以待后续重试。spring业务的实现只会感知运行时异常runtimeexception和内部错误error,只有感知到这两种错误场景才会主动的进行业务回滚。所以,需要将线程异常进行封装。

第二处理子模块336,用于当所述超时判断子模块334判断在所述锁等待超时时间内获取到悲观锁时,获取悲观锁成功,并返回锁记录。

如果在所述锁等待超时时间内,所述future对象获取到了悲观锁,这则说明获取悲观锁成功,正常返回锁记录,其中,所谓的锁记录即为数据锁定记录。

上述图4所示的切面执行模块33的结构组成,仅是举例说明本申请实施例如何执行与所述切入点对应的切面逻辑,以判断是否在所述锁等待超时时间内获取到悲观锁的,而不应构成对本申请的限制。在本申请其他实施例中,切面执行模块33也可以采用其他的组成结构,以判断是否在所述锁等待超时时间内获取到悲观锁。

本申请实施例中,在业务代码被执行的过程中,切入点拦截模块拦截业务代码中的切入点,获取锁等待注解参数,其中,切入点为锁等待注解,业务代码中指定的锁等待超时时间的代码块上标识有该锁等待注解;参数解析模块解析锁等待注解参数,获取指定的锁等待超时时间,指定的锁等待超时时间小于或等于mysql数据库的全局锁等待超时时间;切面执行模块执行与切入点对应的切面逻辑,以判断是否在锁等待超时时间内获取到悲观锁,从而实现了为单个sql任务任意指定mysql悲观锁的锁等待超时时间,满足了不同场景下对锁等待超时时间的个性化需求。此外,由于多个无论什么业务,实施时仅需要在指定的锁等待超时时间的代码块中预先通过注解的方式打上切入点,代码改造量仅仅需要一行,因此,本申请实施例是一种轻量级解决方案,可直接被多个业务系统复用。

设备可以是任何便携式电子设备,包括但不限于手持电脑、平板电脑、移动电话、媒体播放器、个人数字助理(pda),还可以包括其中两项或多项的组合。应当理解,设备只是便携式电子设备的一个示例,设备的组件可以比图示具有更多或更少的组件,或具有不同的组件配置。并且,图中所示的设备的组件可以用硬件、软件或软硬件的组合来实现,包括一个或多个信号处理和/或专用集成电路。

本领域技术人员还可以了解到本申请实施例列出的各种说明性逻辑块、单元和步骤可以通过硬件、软件或两者的结合来实现。至于是通过硬件还是软件来实现取决于特定的应用和整个系统的设计要求。本领域技术人员可以对于每种特定的应用,可以使用各种方法实现所述的功能,但这种实现不应被理解为超出本申请实施例保护的范围。

本申请实施例中所描述的各种说明性的逻辑块,或单元都可以通过通用处理器,数字信号处理器,专用集成电路(asic),现场可编程门阵列或其它可编程逻辑装置,离散门或晶体管逻辑,离散硬件部件,或上述任何组合的设计来实现或操 作所描述的功能。通用处理器可以为微处理器,可选地,该通用处理器也可以为任何传统的处理器、控制器、微控制器或状态机。处理器也可以通过计算装置的组合来实现,例如数字信号处理器和微处理器,多个微处理器,一个或多个微处理器联合一个数字信号处理器核,或任何其它类似的配置来实现。

本申请实施例中所描述的方法或算法的步骤可以直接嵌入硬件、处理器执行的软件模块、或者这两者的结合。软件模块可以存储于ram存储器、闪存、rom存储器、eprom存储器、eeprom存储器、寄存器、硬盘、可移动磁盘、cd-rom或本领域中其它任意形式的存储媒介中。示例性地,存储媒介可以与处理器连接,以使得处理器可以从存储媒介中读取信息,并可以向存储媒介存写信息。可选地,存储媒介还可以集成到处理器中。处理器和存储媒介可以设置于asic中,asic可以设置于用户终端中。可选地,处理器和存储媒介也可以设置于用户终端中的不同的部件中。

在一个或多个示例性的设计中,本申请实施例所描述的上述功能可以在硬件、软件、固件或这三者的任意组合来实现。如果在软件中实现,这些功能可以存储与电脑可读的媒介上,或以一个或多个指令或代码形式传输于电脑可读的媒介上。电脑可读媒介包括电脑存储媒介和便于使得让电脑程序从一个地方转移到其它地方的通信媒介。存储媒介可以是任何通用或特殊电脑可以接入访问的可用媒体。例如,这样的电脑可读媒体可以包括但不限于ram、rom、eeprom、cd-rom或其它光盘存储、磁盘存储或其它磁性存储装置,或其它任何可以用于承载或存储以指令或数据结构和其它可被通用或特殊电脑、或通用或特殊处理器读取形式的程序代码的媒介。此外,任何连接都可以被适当地定义为电脑可读媒介,例如,如果软件是从一个网站站点、服务器或其它远程资源通过一个同轴电缆、光纤电缆、双绞线、数字用户线(dsl)或以例如红外、无线和微波等无线方式传输的也被包含在所定义的电脑可读媒介中。所述的碟片(disk)和磁盘(disc)包括压缩磁盘、镭射盘、光盘、dvd、软盘和蓝光光盘,磁盘通常以磁性复制数据,而碟片通常以激光进行光学复制数据。上述的组合也可以包含在电脑可读媒介中。

以上所述的具体实施例,对本申请的目的、技术方案和有益效果进行了进一步详细说明,所应理解的是,以上所述仅为本申请实施例的具体实施例而已,并不用 于限定本申请的保护范围,凡在本申请的精神和原则之内,所做的任何修改、等同替换、改进等,均应包含在本申请的保护范围之内。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1