9

这是我第一次尝试 Spring3 的 @Scheduled ,但发现我无法提交到 DB。这是我的代码:

@Service
public class ServiceImpl implements Service , Serializable
{
  @Inject 
  private Dao dao;

  @Override
  @Scheduled(cron="0 0 * * * ?") 
  @Transactional(rollbackFor=Exception.class)
  public void hourly()
  {
    // get xxx from dao , modify it
    dao.update(xxx);
  }
}

我认为它应该可以工作,我可以看到它每小时启动并从 DB 加载 xxx ,但数据没有提交给 DB。

tx:annotation-drivenspring 的 xml 中有:

<bean id="entityManagerFactoryApp" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="myapp"/>
</bean>
<bean id="transactionManagerApp" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManagerFactoryApp" />
</bean>

<tx:annotation-driven transaction-manager="transactionManagerApp" />

有人可以告诉我我在这里错过了什么吗?

我有一个“肮脏”的解决方案:

@Service
public class ServiceImpl implements Service , Serializable
{
  @Inject 
  private Dao dao;

  @Inject
  @Qualifier("transactionManagerApp")
  private PlatformTransactionManager txMgrApp;

  @Override
  @Scheduled(cron="0 0 * * * ?")
  @Transactional(rollbackFor=Exception.class)
  public void hourly()
  {
    final TransactionTemplate txTemplateApp = new TransactionTemplate(txMgrApp);
    txTemplateApp.execute(new TransactionCallbackWithoutResult()
    {
      @Override
      protected void doInTransactionWithoutResult(TransactionStatus status)
      {
        //get xxx from dao
        dao.update(xxx);
      }
    });
  }
}

它在这里工作得很好,但它太多余了,使代码更难阅读。我想知道为什么在前面的代码片段中没有注入(和打开)TransactionManager ?

非常感谢 !

4

3 回答 3

19

您可能已经弄清楚或继续前进(我希望如此),但为了他人的利益:

@Transactional注释告诉 SpringServiceImpl用一个也实现了 ' ' 的动态代理来包装你的原始 bean (Service默认情况下 Spring 代理接口,而不是实现)。hourly() 当您调用代理时,此代理将透明地处理事务的创建和提交/回滚。但是,如果您hourly()直接调用您的实现(这就是上面发生的情况),代理将被绕过,因此没有事务。

http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/

解决方案是

  1. 正如您在“脏”解决方案中所做的那样,以编程方式划分事务(在这种情况下您不需要注释)。
  2. 确保您的 @Scheduled 方法dao.update(xxx);通过 Service 接口进行调用,而不是直接在您的实现上(从而通过代理)。基本上,您需要将该@Scheduled方法移至另一个 bean。

我希望这足够清楚!

于 2012-10-18T14:53:31.917 回答
0

当您使用注释驱动支持时,它仅适用于在该上下文中创建的类。我敢打赌,ServiceImpl 不是在与事务管理器相同的上下文中创建的(直接或通过注释扫描)。

于 2011-03-26T17:19:01.543 回答
0

我遇到了同样的问题,在花了一些时间之后,我意识到在 dao.update() 调用一些不检查空值的不相关代码后出现异常 - 所以它只是破坏了事务。没有 stackTrace 打印,因为它已被 spring 处理好(一些 catch 块)。我花了一段时间。所以 - 只需验证您的交易方法是否完成直到结束。希望它会帮助某人。

约西列夫

于 2015-04-26T16:48:28.913 回答