【问题标题】:Spring3 's @Transactional @Scheduled not committed to DB?Spring3 的 @Transactional @Scheduled 未提交给数据库?
【发布时间】:2011-07-23 13:36:15
【问题描述】:

这是我第一次尝试 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。

spring 的 xml 中有 tx:annotation-driven

<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" />

谁能告诉我我在这里错过了什么?

我有一个“dirty”解决方案:

@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);
      }
    });
  }
}

这里工作正常,但它太多余了,使代码更难阅读。 不知道为什么在之前的代码sn-ps中TransactionManager没有被注入(并被打开)?

非常感谢!

【问题讨论】:

  • 有点跑题了,但对于@Transactional,您不需要rollbackFor。对于运行时异常,总是隐式进行回滚。
  • 我尝试了你的肮脏解决方案,但它不起作用。知道为什么吗?

标签: spring dependency-injection scheduling transactional spring-3


【解决方案1】:

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

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

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

解决方案是

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

我希望这已经足够清楚了!

【讨论】:

  • 那么关于你的第二个解决方案 - 你是什么意思?
  • 按照第二个解决方案所说的去做。将@@Transactional 方法移动到另一个注入@@Scheduled bean 的bean 中,事务现在还活着!否则我不断收到“javax.persistence.TransactionRequiredException: No transactional EntityManager available”
【解决方案2】:

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

【讨论】:

  • 谢谢,但是如何“强制”在与我的 transactionManager 相同的上下文中创建的 ServiceImpl ?
  • 要么使用该类显式创建一个 bean,要么确保您的组件扫描标记位于事务管理器的相同配置或父配置中。
  • 嗨,你能说得更具体一点吗?我不想在 XML 文件中手动创建 serviceBean。但我不清楚“组件扫描标签在同一配置或 txManager 的父级中”?事实上,“context:component-scan”和 在同一个配置中!但为什么它不起作用?
  • 现在你正在做一些事情;因为您在同一个配置文件中定义了组件扫描和注释驱动,所以我很茫然。我会给你一个 +1 并希望有人能最好的回答我。
【解决方案3】:

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

约西·列夫

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-26
    • 1970-01-01
    • 2019-06-18
    • 2019-09-30
    • 2012-12-15
    • 2013-05-26
    • 2011-08-29
    • 2011-03-21
    相关资源
    最近更新 更多