走自己的路

路漫漫其修远兮,吾将上下而求索

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  50 随笔 :: 4 文章 :: 118 评论 :: 0 Trackbacks
由于业务需要将quartz的jobstore从JobStoreTx更新为JobStoreCMT,接着启动servlet时发现被锁住了。由于使用jobstorecmt我们使用了managed datasource,按照quartz文档的要求我也配置了non managed datasource,在quartz中什么是managed datasource和non managed datasource呢?

Managed datasource: 使用了cmt才有的概念,应该主要是job执行时还有一些其他和job有关的操作quartz会用到的datasource,这个datasource是由容器来管理的,也就是一般意义上我们使用的managed datasource,但是它还强调的是transaction是由容器或者用户自己的程序来控制(JTA)。quartz的job执行提供了一个UserTransaction的wrap。

Non managed datasource; JobStoreTX默认就是使用这个datasource,默认是dbcp的pool,这个non managed datasource不是指我们不能使用容器管理的datasource,也可以配置成容器管理的datasource的,但要注意的是transaction level是local的,transaction是由quartz控制的,quartz来完成transaction的语义和边界。


一开始的配置如下:
# The value of org.quartz.scheduler.instanceName
# can be any string
, and has no meaning to the scheduler itself -
# but rather serves as a mechanism for client code to distinguish schedulers
# when multiple instances are used within the same program.  If you are using
# the clustering features
, you must use the same name for every instance in 
# the cluster that is 'logically' the same Scheduler.
#
# NOTE: Especially for the application using LTS
, the instanceName is different and 
#       specific per application to avoid the interruption between applications. For
#       example in TMS project the instanceName could be named as TMS_APP
, in DMS
#       project the instanceName could be named as DMS_APP etc
, the instanceName in
#       different projects must be different. For more details
, you could refer to
#       the LTS installation guide.
org.quartz.scheduler.instanceName 
= LTS
org.quartz.scheduler.rmi.export 
= true
org.quartz.scheduler.rmi.registryHost 
= localhost
org.quartz.scheduler.rmi.registryPort 
= 1100
org.quartz.scheduler.rmi.createRegistry 
= as_needed
org.quartz.scheduler.wrapJobExecutionInUserTransaction 
= true


org.quartz.threadPool.class 
= org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount 
= 10
org.quartz.threadPool.threadPriority 
= 5
org.quartz.jobStore.misfireThreshold 
= 2592000000


org.quartz.jobStore.class 
= org.quartz.impl.jdbcjobstore.JobStoreCMT


org.quartz.jobStore.driverDelegateClass 
= org.quartz.impl.jdbcjobstore.oracle.OracleDelegate

org.quartz.jobStore.useProperties 
= false
org.quartz.jobStore.dataSource 
= myXADS
org.quartz.jobStore.nonManagedTXDataSource 
= myDS
org.quartz.jobStore.tablePrefix 
= QRTZ_
org.quartz.jobStore.isClustered 
= false
org.quartz.jobStore.selectWithLockSQL 
= 

org.quartz.dataSource.myXADS.jndiURL 
= jdbc/ltstxxatest

org.quartz.dataSource.myDS.driver 
= oracle.jdbc.OracleDriver
org.quartz.dataSource.myDS.URL 
= jdbc:oracle:thin:@shhpdv11:1521:WOSDB
org.quartz.dataSource.myDS.user 
= sysint
org.quartz.dataSource.myDS.password 
= sysint
org.quartz.dataSource.myDS.maxConnections 
= 5






datasource的配置:
    <managed-data-source name="LTSTxTestXADataSource"
        connection-pool-name
="LTSTxTestXAConnectionFactory"
        jndi-name
="jdbc/ltstxxatest" tx-level='global' />
    
<!-- tx-level='global' -->
    
<connection-pool name="LTSTxTestXAConnectionFactory">
        
<connection-factory
            
factory-class="oracle.jdbc.xa.client.OracleXADataSource"
            user
="sysint" password="sysint"
            url
="jdbc:oracle:thin:@shhpdv11:1521:WOSDB">
        
</connection-factory>
    
</connection-pool>

但是发现servlet在启动时hold在那里了,跟了一下代码,发现quartz jobstoreCMT默认是使用的oracle db的TM锁,而jobstoreTX使用的是java的逻辑锁,于是登录到db中,查了一下,发现一个insert quartz_simple_triggers的DML操作申请了Qaurtz_Locks的表锁,而接着start quartz scheduler时也会去申请这个表锁,但是前面的DML操作一直都没有commit,所有quartz scheduler start时就被锁在那里了。然后试着将non managed datasource和managed datasource配成同一个datasource启动ok没有问题,但是正是因为配了同一个datasource可能下一次从pool中拿的connection的oracle session还是拥有那个锁资源的,锁资源没有被先前的connection释放掉,因为事务没有提交,connection的逻辑close不会释放session拥有的资源。这样又回到了原点,白试了一把,后来仔细跟了一把程序,发现autocommit是false,也没有地方显著的提交,scheduleJob和unscheduleJob都会有这种情况,本来以为只有job执行的时候会用到managed datasource,这样看来很多对job信息的处理的地方都用到了managed datasource,但是为什么quartz不帮我们wrap起来提交呢,控制transaction的任务交给了我们自己或container,交给我们自己是指我们需要自己用JTA transaction封装这些操作,交给container就需要把属性:

org.quartz.jobStore.dontSetAutoCommitFalse = true

但是quartz文档中提到下面这一段:

org.quartz.jobStore.dontSetAutoCommitFalse

False

Description: Setting this parameter to true tells Quartz not to call setAutoCommit(false) on connections obtained from the DataSource(s). This can be helpful in a few situations, such as if you have a driver that complains if it is called when it is already off. This property defaults to false because most drivers require that setAutoCommit(false) be called.


大概意思是大多数jdbc driver是不用去设置auto commit为true的,保持默认值是false就可以了,又看到了这篇文章:

http://forums.opensymphony.com/thread.jspa?threadID=14762&messageID=28963#28963

主要是说auto commit设成true会改变quartz transaction的语义,本来时多步操作提交的,现在变成了每步dml操作都会提交。但是如果不设auto commit在oracle jdbc中似乎没办法再提交这个transaction了,锁就不会被释放。于是找了找,找到了下面这篇文章:

http://forums.opensymphony.com/thread.jspa?threadID=365430&messageID=452688#452688

这篇文章也遇到了类似这样的问题,提交了trigger但是没有到db中,应该也是被锁住了。提出的解决办法就是把auto commit设成true。接着尝试了一下,顺利成功启动,trigger成功调度,job成功执行。表面上看似没有什么问题,但是一直还是有concern,因为我们这样设置会不会更改了quartz事务的语义,仔细看了quartz jobstore相关的代码,jobstorecmt中其实还有一个属性:

    // Great name huh?
    protected boolean dontSetNonManagedTXConnectionAutoCommitFalse = false;

文档中的描述:

org.quartz.jobStore.dontSetNonManagedTX ConnectionAutoCommitFalse

False

Description: This is the same as the property org.quartz.jobStore.dontSetAutoCommitFalse, except that it applies to the nonManagedTXDataSource.


默认值是false,所有non managed datasource都是用的这个值,auto commit是false,设置org.quartz.jobStore.dontSetAutoCommitFalse = false不会影响non managed datasource的transaction语义。这样想想把这个值设成true也不会有什么问题,不过进一步还是要进行大量的测试。所以oracle application server使用jobstorecmt后quartz的配置应该如下:

# The value of org.quartz.scheduler.instanceName
# can be any string
, and has no meaning to the scheduler itself -
# but rather serves as a mechanism for client code to distinguish schedulers
# when multiple instances are used within the same program.  If you are using
# the clustering features
, you must use the same name for every instance in 
# the cluster that is 'logically' the same Scheduler.
#
# NOTE: Especially for the application using LTS
, the instanceName is different and 
#       specific per application to avoid the interruption between applications. For
#       example in TMS project the instanceName could be named as TMS_APP
, in DMS
#       project the instanceName could be named as DMS_APP etc
, the instanceName in
#       different projects must be different. For more details
, you could refer to
#       the LTS installation guide.
org.quartz.scheduler.instanceName 
= LTS
org.quartz.scheduler.rmi.export 
= true
org.quartz.scheduler.rmi.registryHost 
= localhost
org.quartz.scheduler.rmi.registryPort 
= 1101
org.quartz.scheduler.rmi.createRegistry 
= as_needed
org.quartz.scheduler.wrapJobExecutionInUserTransaction 
= true


org.quartz.threadPool.class 
= org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount 
= 10
org.quartz.threadPool.threadPriority 
= 5
org.quartz.jobStore.misfireThreshold 
= 2592000000


org.quartz.jobStore.class 
= org.quartz.impl.jdbcjobstore.JobStoreCMT


org.quartz.jobStore.driverDelegateClass 
= org.quartz.impl.jdbcjobstore.oracle.OracleDelegate

org.quartz.jobStore.useProperties 
= false
org.quartz.jobStore.dataSource 
= myXADS
org.quartz.jobStore.nonManagedTXDataSource 
= myDS
org.quartz.jobStore.tablePrefix 
= QRTZ_
org.quartz.jobStore.isClustered 
= false
org.quartz.jobStore.dontSetAutoCommitFalse 
= true
org.quartz.jobStore.selectWithLockSQL 
= 

org.quartz.dataSource.myXADS.jndiURL 
= jdbc/ltstxxatest


org.quartz.dataSource.myDS.driver 
= oracle.jdbc.OracleDriver
org.quartz.dataSource.myDS.URL 
= jdbc:oracle:thin:@shhpdv11:1521:WOSDB
org.quartz.dataSource.myDS.user 
= sysint
org.quartz.dataSource.myDS.password 
= sysint
org.quartz.dataSource.myDS.maxConnections 
= 5




posted on 2009-02-06 17:13 叱咤红人 阅读(3550) 评论(2)  编辑  收藏 所属分类: Other Java and J2EE frameworks

评论

# re: Oracle application server使用Quartz JobStoreCMT遇到程序被锁问题 2009-06-25 17:00 Tenny
楼主:
 我因为项目需要也是将quartz的jobstore从JobStoreTx更新为JobStoreCMT,我在servlet启动时没错,但是当我调度执行一个job时,在持久化存储job的Blob信息时出错:
配置环境:weblogic9.22 + oracle 10g + quartz1.6
org.quartz.JobPersistenceException: Couldn't store job: Driver's Blob representation is of an unsupported type: weblogic.jdbc.wrapper.Blob_oracle_sql_BLOB [See nested exception: java.sql.SQLException: Driver's Blob representation is of an unsupported type: weblogic.jdbc.wrapper.Blob_oracle_sql_BLOB]
....
Caused by: java.sql.SQLException: Driver's Blob representation is of an unsupported type: weblogic.jdbc.wrapper.Blob_oracle_sql_BLOB
...
我更新了oracle10g的最新jdbc驱动亦于事无补.我也不确信我的quartz配置是否正确,请帮我检查一下:
org.quartz.scheduler.instanceName = OnlineTaskQuartzScheduler
#org.quartz.scheduler.rmi.export = true
#org.quartz.scheduler.rmi.registryHost = localhost
#org.quartz.scheduler.rmi.registryPort = 1101
#org.quartz.scheduler.rmi.createRegistry = as_needed
org.quartz.scheduler.wrapJobExecutionInUserTransaction = true

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5
org.quartz.jobStore.misfireThreshold = 2592000000


org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT


org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate

org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myXADS
org.quartz.jobStore.nonManagedTXDataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = false
org.quartz.jobStore.dontSetAutoCommitFalse = true
org.quartz.jobStore.selectWithLockSQL =

org.quartz.dataSource.myXADS.jndiURL = ReportDataSource
org.quartz.dataSource.myXADS.jndiAlwaysLookup = DB_JNDI_ALWAYS_LOOKUP
org.quartz.dataSource.myXADS.java.naming.factory.initial = weblogic.jndi.WLInitialContextFactory
org.quartz.dataSource.myXADS.java.naming.provider.url = t3://localhost:7001
org.quartz.dataSource.myXADS.java.naming.security.principal = weblogic
org.quartz.dataSource.myXADS.java.naming.security.credentials = weblogic


org.quartz.dataSource.myDS.driver = oracle.jdbc.OracleDriver
org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@XXXXXXX:1521:dhcs
org.quartz.dataSource.myDS.user = XXXXX
org.quartz.dataSource.myDS.password = XXXXX
org.quartz.dataSource.myDS.maxConnections = 5
org.quartz.dataSource.myDS.validationQuery = select table_name from user_tables   回复  更多评论
  

# re: Oracle application server使用Quartz JobStoreCMT遇到程序被锁问题 2009-06-26 05:10 ldd600
请使用 WebLogicDelegate  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: