spring transaction timeout不起作用

时间:2011-09-06 07:10:42

标签: java spring transactions

如果事务运行时间过长,我会尝试停止/回滚事务。但是通过配置spring的事务管理器的timeout属性似乎不起作用。 我的环境:

  1. spring 2.5.6 + JPA + hibernate 3.2.6
  2. oracle 10g
  3. jdk 1.6.0_17
  4. 由于spring有助于管理我的交易,因此配置如下:

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean 
        below) -->
    <tx:advice id="defaultTxAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- Keep SequenceService in a isolation transaction -->
            <tx:method name="get*" read-only="true" />
            <!-- By default, A runtime exception will rollback transaction. -->
            <tx:method name="*" timeout="10" rollback-for="ApplicationException" />
        </tx:attributes>
    </tx:advice>
    

    我有一个TicketService,它会将一些记录插入数据库,只需让它再睡15秒。

    public class DefaultTicketService implements TicketService{
        public void sell() {
            // checking and insert some records to underlying database
            ....
            // sleep to reach the transaction deadline
            try {Thread.sleep(15 * 1000);} catch(Exception e){}
        }
    }
    

    此外,我修改了spring的 org.springframework.orm.jpa.JpaTransactionManager 以输出更多调试信息。

    protected void doBegin(Object transaction, TransactionDefinition definition) {
        ... ...        
        // Register transaction timeout.
        int timeout = determineTimeout(definition);
        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
            if (logger.isDebugEnabled()) {
                logger.debug("****setTimeoutinSeconds(" + timeout
                        + " seconds) to EntityManager(" + txObject.getEntityManagerHolder()
                        + "), the transaction begin time:"
                        + new Date(System.currentTimeMillis()));
            }
            txObject.getEntityManagerHolder().setTimeoutInSeconds(timeout);
        }
        ... ... 
    }
    
    protected void doCommit(DefaultTransactionStatus status) {
        JpaTransactionObject txObject = (JpaTransactionObject) status.getTransaction();
        if (status.isDebug()) {
            logger.debug("Committing JPA transaction on EntityManager ["
                    + txObject.getEntityManagerHolder().getEntityManager() + "]");
        }
        try {
            if (status.isDebug()) {
                logger.debug("The deadline of entityManager("
                        + txObject.getEntityManagerHolder().getEntityManager() + "):"
                        + txObject.getEntityManagerHolder().getDeadline() + ", and current time:"
                        + new Date(System.currentTimeMillis()));
            }
            EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager()
                    .getTransaction();
            tx.commit();
        ... ...
    }
    

    完成测试后,结果超出我的预期,交易最后提交。以下是测试的输出:

    [JpaTransactionManager] Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@350225] for JPA transaction
    [JpaTransactionManager] ****[Begin]timeout:10 seconds,The deadline of entityManager(org.hibernate.ejb.EntityManagerImpl@350225):null, and current time:Tue Sep 06 15:05:42 CST 2011
    [JpaTransactionManager] Exposing JPA transaction as JDBC transaction [SimpleConnectionHandle: com.mchange.v2.c3p0.impl.NewProxyConnection@1eb41d6]
    [JpaTransactionManager] Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@350225] for JPA transaction
    ... ...
    [JpaTransactionManager] Initiating transaction commit
    [JpaTransactionManager] Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@350225]
    [JpaTransactionManager] ****[Commit]The deadline of entityManager(org.hibernate.ejb.EntityManagerImpl@350225):Tue Sep 06 15:05:52 CST 2011, and current time:Tue Sep 06 15:05:58 CST 2011
    [JpaTransactionManager] Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@350225] after transaction
    [EntityManagerFactoryUtils] Closing JPA EntityManager
    

    从调试信息来看,显然当前时间已超过截止日期,那么为什么spring不会回滚事务?在我的理解中,如果我设置超时,例如10秒,Spring将在启动新事务时启动Timer,如果计时器达到时间限制,它将回滚事务。你能告诉我为什么???

    更新&GT;&GT;

    当经历JavaEE7的教程时,发现似乎JPA2.1提供了对锁超时的支持(一般事务超时是由获取锁的超时引起的。)

    http://docs.oracle.com/javaee/7/tutorial/doc/persistence-locking002.htm

    42.2.2.1悲观锁定超时

2 个答案:

答案 0 :(得分:1)

答案 1 :(得分:0)

经过一番研究,我发现问题在于TimerTask线程没有使用通常启动和提交事务的弹簧代理。从理论上讲,你可以手动将支持编码到你的TimerTask中以使用代理,但这对我来说似乎很麻烦。

Spring拥有自己的调度框架,您可以使用它而不是TimerTask来执行runnables,并且不需要太多的代码更改来代替使用。

这是文档:

http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/scheduling.html