转自:http://bbs.chinaunix.net/thread-3685716-1-1.html
近来研究定时器Quartz集群的实现原理时,发现了一种利用数据库锁的方式来实现集群环境下进行并发控制的方式。由于现在的系统多是部署在集群环境中,需要进行并发控制时,这是一种很好的实现方法,现将原理介绍如下:
首先,在数据库中建立一张拥有锁标识的表,建立表的SQL语句如下:
CREATE TABLE TB_LOCKS
( LOCK_NAME VARCHAR2(40) NOT NULL,
PRIMARY KEY (LOCK_NAME)
)
表创建好之后,插入一些数据,这些数据是根据数据库的业务逻辑操作抽象出的系统所拥有的表的类型,如"TRIGGER_ACCESS"就表示对任务触发器相关的信息进行修改删除操作时所需要获得的锁。每当要进行与某种业务相关的数据库操作时,先去这张表中查询操作相关的业务对象所需要的锁,如Quartz中需要修改触发器的状态,下次触发时间时,就需要获得"TRIGGER_ACCESS"所表示的锁。这时,执行查询这个表数据的SQL形如“select
* from TB_LOCKS t where t.lock_name='TRIGGER_ACCESS' for update”,在select之后加了“for update”,就如JAVA语言中的为方法加上synchronized一样,起到了串形化访问修改所需数据的作用。当一个线程使用上述的SQL对表中的数据执行查询操作时,若查询结果中包含相关的行,数据库就会对这些行进行ROW LOCK。若此时又有另外一个线程使用相同的SQL对表的数据进行查询时,由于查询出的数据行已经被数据库锁住了,此时这个线程就只能等待,直到拥有这些行锁的线程完成了相关的业务操作,执行了commit动作后,数据库才会释放了相关行的锁,这个线程才能继续执行。通过这样的机制,在集群环境下,结合乐观锁的机制就可以防止一个线程对数据库数据的操作的结果被另外一个线程所覆盖,从而可以避免一些难以觉察的错误发生。
PS by self : for update使用的是悲观锁,然后结合triggers表中的PREV_FIRE_TIME timestamp的乐观锁机制。
当然,达到这种效果的前提是需要把Connection设置为手动提交,即autoCommit为false,下面是执行相关步骤的程序代码:
/**
* Execute the given callback having optionally aquired the given lock.
* This uses the non-managed transaction connection.
*
* @param lockName The name of the lock to aquire, for example
* "TRIGGER_ACCESS". If null, then no lock is aquired, but the
* lockCallback is still executed in a non-managed transaction.
*/
protected Object executeInNonManagedTXLock(String lockName,
TransactionCallback txCallback) throws JobPersistenceException {
boolean transOwner = false;
Connection conn = null;
try {
if (lockName != null) {
if (getLockHandler().requiresConnection()) {
conn = getNonManagedTXConnection();
}
//获得相关的锁,通过带有"for update"的select语句实现,如果这个锁被其他线程占用,执行这个操作的线程只能等待
transOwner = getLockHandler().obtainLock(conn, lockName);
}
if (conn == null) {
conn = getNonManagedTXConnection();
}
Object result = txCallback.execute(conn);//执行相关的业务逻辑操作,获得操作的结果
commitConnection(conn);//提交操作结果,释放锁
return result;
} catch (JobPersistenceException e) {
rollbackConnection(conn);//撤销操作结果,释放锁
throw e;
} catch (RuntimeException e) {
rollbackConnection(conn);//撤销操作结果,释放锁
throw new JobPersistenceException("Unexpected runtime exception: "
+ e.getMessage(), e);
} finally {
try {
releaseLock(conn, lockName, transOwner);
} finally {
cleanupConnection(conn);
}
}
}
分享到:
相关推荐
NULL 博文链接:https://daoshud1.iteye.com/blog/1955099
一个基于springboot的quartz集群dome。 向http://localhost:9090/job/addjob注入3个参数 类名:(及时定时任务的类如:com.ybjdw.site.job.NewJob) 组名:随意 定时启动方法:如“0/3 * * * * ?”(每3秒启动一次...
spring 集成quartz定时任务 用数据库实现quartz的集群
java + quartz实现定时任务,实现集群配置,在集群环境下多节点运行定时Quartz定任务,就会存在重复处理任务的现象,为解决这一问题,下面我将介绍使用 Quartz 的 TASK ( 12 张表)实例化到数据库,基于数据库自动...
自己弄了将近一天的成果。主要是修改MethodInvokingJobDetailFactoryBean这个类。
本人花费多日时间,亲测有效。所需文件代码完整,只需导入常用开发IDE和mysql数据库即可正常使用。
NULL 博文链接:https://kissroom112.iteye.com/blog/2224442
NULL 博文链接:https://vista-move.iteye.com/blog/2274246
quartz在集群环境下的最终解决方案quartz在集群环境下的最终解决方案
需要把app部署在多台服务器上,但只能让其中一台服务器的job执行,一台服务器挂了,另一台还能继续执行job,通过网上查找资料,都是java工程的方式,不好部署并测试,经过二天辛苦整合,终于整理成一个单spring web...
各种企业应用几乎都会碰到任务调度的需求...对于一个典型的MIS系统来说,在每月1号凌晨统计上个月各部门的业务数据生成月报表,每半个小时查询用户是否已经有快到期的待处理业 务……,这样的例子俯拾皆是,不胜枚举。
spring4.0.6+quartz 2.2.3 集群示例
最近项目中使用了spring+Quartz定时任务、但是项目最近要集群部署、多个APP下如何利用Quartz 协调处理任务。 大家可以思考一下、现在有 A、B、C三个应用同时作为集群服务器对外统一提供服务、每个应用下各有一个...
spring quartz
spring 定时器 内含TimerTask实现和Quartz实现两种方式
spring quartz类全包spring quartz类全包
Spring整合Quartz定时任务 在集群、分布式系统中的应用
Spring Quartz 定时器示例(Web工程版),欢迎下载。
java中spring quartz定时任务demo,里面包含项目所需的quartz.jar, spring.jar包,配置文件等,可直接运行使用
NULL 博文链接:https://soulshard.iteye.com/blog/337886