【问题标题】:How to force a new record to be saved to the database *immediately*?如何强制将新记录*立即*保存到数据库中?
【发布时间】:2013-02-13 12:42:30
【问题描述】:

我正在开发一个带有两个线程的 Java/Seam/Hibernate/Glassfish 应用程序:

  • 线程 #1 发送各种消息并将摘要信息写入 MySQL 数据库。
  • 线程 #2 定期轮询数据库(由 ScheduledExecutorService 调用)并作用于每条消息的当前“状态”。

遇到了一个集成测试问题:Thread #2 等待 Thread #1 添加新行的时间似乎并不重要,它只是在测试期间没有添加,因此没有进行预期的调用。果然,在测试失败后会弹出一个新行——但为时已晚。不确定这是否是设计问题 - Thread #2 当前使用 Lifecycle.beginCall()...Lifecycle.endCall() 获取 Seam 上下文。所以我的理解(这可能是错误的)可能是因为两个线程有​​两个单独的 Hibernate 会话 - 所以一个阅读不知道来自一个写作的最新信息?

可能有不同的方法来解决这个问题,但我目前的想法是,当我调用 save() / flush() 甚至手动提交事务时,我不能强迫 Hibernate 立即将记录添加到表中吗?这些都不走运——让我想知道是否在幕后使用了某种托管事务。感谢您的任何建议...

有关信息,以下是添加记录的代码要点:

// Obtain Hibernate session
Session session = (Session) Component.getInstance("hibernateSession");

// Create request
Request newRequest = new Request();
// newRequest.set<blah>();

// Save the new request to the database
session.save(newRequest);

// Have tried session.flush(), transaction.commit() etc. here.
// Nothing seems to put the record into the database straight away.

不确定这是否相关,但这里是 Hibernate 配置:

<property name="transaction.flush_before_completion">true</property>
<property name="connection.release_mode">after_statement</property>
<property name="transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</property>
<property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="current_session_context_class">jta</property>

(由于这是客户拥有的现有应用程序,我无权更改 Hibernate 配置。)

【问题讨论】:

    标签: java hibernate transactions glassfish seam


    【解决方案1】:

    你猜对了。

    您使用的是JTATransactionFactory,因此事务由 JTA(即容器)划分。

    您用于保存Request 的方法(这里我假设它是在 EJB 中定义的)需要使用事务注释进行注释:@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW),因此当方法结束时,事务将被提交。

    【讨论】:

    • 嗯,这看起来不错,可能接近标记,但该方法不在 EJB 中。我尝试了 Seam 的 @Transactional 属性,但这没有任何区别……有什么建议吗?
    • (我可能应该提到它是Seam v2.2.1)。
    【解决方案2】:

    非常感谢@Carlo Pellegrini,他的回答为我指明了正确的方向。从那以后,我遇到了this answer,并在 save() 操作后尝试了以下代码:

    // Commit Seam-managed transaction (if there is one)
    UserTransaction userTransaction = (UserTransaction) Component.getInstance("org.jboss.seam.transaction.transaction");
    if (userTransaction.isActive()) {
        userTransaction.commit();
    }
    

    它很好地完成了这项工作,但我不喜欢它 - 似乎有点 hacky!有没有更好的办法?

    【讨论】:

      猜你喜欢
      • 2021-02-17
      • 2012-03-26
      • 1970-01-01
      • 1970-01-01
      • 2011-11-16
      • 1970-01-01
      • 2019-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多