集群环境下防止并发的一种实现( Spring Quartz 集群思路)
2014-08-29 10:57
465 查看
转自:http://bbs.chinaunix.net/thread-3685716-1-1.html
近来研究定时器Quartz集群的实现原理时,发现了一种利用数据库锁的方式来实现集群环境下进行并发控制的方式。由于现在的系统多是部署在集群环境中,需要进行并发控制时,这是一种很好的实现方法,现将原理介绍如下:
首先,在数据库中建立一张拥有锁标识的表,建立表的SQL语句如下:
表创建好之后,插入一些数据,这些数据是根据数据库的业务逻辑操作抽象出的系统所拥有的表的类型,如"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,下面是执行相关步骤的程序代码:
近来研究定时器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); } } }
相关文章推荐
- 集群环境下防止并发的一种实现
- spring boot 整合 quartz 集群环境 实现 动态定时任务配置【原】
- spring security 在没实现session共享的集群环境下 防止用户多次登录的 实现思路
- Spring1.1.1+quartz1.8.6实现集群环境下的定时任务
- spring结合Quartz的集群功能实现
- AFN实现并发结束后回调拦截的一种思路
- Spring整合Quartz定时任务 在集群、分布式系统中的应用(Mysql数据库环境)
- 如何用Spring实现集群环境下的定时任务
- 如何用Spring实现集群环境下的定时任务
- Spring 整合Quartz 2实现定时任务五:集群、分布式架构实现探讨
- Quartz - Spring集成Quartz实现集群的定时任务
- 集群环境下的Spring Quartz
- Spring+quartz 实现定时任务job集群配置【原】
- Spring+quartz实现集群任务调度
- 万物生长 项目jar包越少越好,不然会导致eclipse进入断点延迟高,很慢. Spring+quartz 实现定时任务job集群配置
- Windows怎样实时同步文件夹?Java+Spring+Quartz+Tomcat集群实现
- Spring 整合Quartz 2实现定时任务五:集群、分布式架构实现探讨
- quartz集群分布式(并发)部署解决方案-Spring
- quartz集群分布式(并发)部署解决方案-Spring
- Spring+quartz实现定时任务集群