【问题标题】:Understanding JTA in EJB: Not flushing理解 EJB 中的 JTA:不刷新
【发布时间】:2012-04-06 12:46:24
【问题描述】:

所以我在类级别用@TransactionAttribute(TransactionAttributeType.REQUIRED) 注释了这个EJB,这样每个方法都应该在事务中执行,除非我覆盖这个行为,当事务提交时,数据应该被刷新,对吧?到目前为止,一切都很好。 所以现在我有一个public User find(String email) 方法,用@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) 注释,所以这个方法不会在事务中执行,因为它只获取数据。

好的,我正在测试我的应用程序,我有一个引导程序方法,它使用 ejb 创建几个实体,然后使用 find 方法获取一个。 在我看来,应该发生什么:

->我创建实体 1 调用 save(User u),它在事务中执行。它提交,数据被刷新。

->对另外 2 个实体重复此步骤。他们的事务提交,数据被刷新。

->此时我的二级缓存(使用 Eclipselink)和数据库中应该有 3 个实体。

->我调用find(String email) 方法。它找到一个实体,返回它,没有异常,我的代码执行得很好,我很兴奋,我打开啤酒,我不需要在 stackoverflow 中提问。

实际发生的情况:

->我创建了所有 3 个实体。也不例外。

->我调用find(String email)方法,因为没有找到实体,所以引发了EjbException,调试发现调用这个方法时,数据库是空的,没有数据被刷新(即使当我显式创建实体时,我调用了 flush 方法,无论如何这都不应该)。它抛出 EJbException,我的代码停止,我再次检查数据库,现在实体在那里,一旦抛出异常,因为它们不在那里。 如果我从 find 方法中删除 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED),这会导致它在事务中执行搜索,我的代码就可以工作。

->我不开啤酒。

所以现在说真的,发生了什么事?为什么我需要在事务中搜索实体,否则它不会刷新任何内容?

编辑:持久性单元:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="TribunalExpedientes" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>tribunalexpedientes</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <shared-cache-mode>ALL</shared-cache-mode>
     <properties>
      <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
     </properties>
  </persistence-unit>
</persistence>

没有引发异常,除了说我搜索时没有找到实体,之后缓存被刷新到数据库。

【问题讨论】:

    标签: jpa ejb eclipselink jta


    【解决方案1】:

    我的猜测是你没有正确配置东西。包括您的 persistence.xml 以及您正在使用的应用程序服务器和数据库。

    您使用的是 JTA 还是 RESOURCE_LOCAL,您应该使用 JTA 并且应该在您的 persistence.xml 中设置您的目标服务器。

    还要检查是否有任何错误。如果发生错误,则事务将被回滚。

    NOT_SUPPORTED 通常不是一个好主意,这意味着如果在事务中调用此方法将引发异常。这可能是正在发生的事情。

    【讨论】:

    • 即“NEVER”属性,NOT_SUPPORTED 挂起事务(如果处于活动状态),或者如果不处于活动状态,则在事务外部执行方法。它使该方法成为非事务性方法。如果在事务中调用该方法,它不会引发异常。
    • 那么如果你使用 NEVER 代替,你会得到异常吗?
    • @Chris 我得到一个例外是的!它说:javax.ejb.EJBException: EJB cannot be invoked in global transaction,你是对的,事务没有提交,启动了一个“全局”事务。为什么?这是某种优化吗?我从 RequestScoped CDI bean 调用,该 bean 是非事务性的。不知道怎么回事
    【解决方案2】:

    添加将显示语句何时执行以及事务何时提交。由于 NOT_SUPPORTED 暂停了事务,因此只有在先前的事务已提交时,您才能“找到”数据。您的保存方法很有可能包含在您的查找方法暂停的较大事务中。 Flush 不会改变这一点,因为这些数据仍然是事务隔离的。

    尝试使用 REQUIRES_NEW 将保存方法放入它们自己的事务中,这些事务在完成时会被提交。

    【讨论】:

      【解决方案3】:

      嗯,提交事务不需要 Eclipselink 刷新数据。这就是原因。在我看来,这是一个非常丑陋的行为。 Eclipselink 可以在需要时刷新数据。我也有一些问题。例如。使用@PrePersist 或@PreUpdate 时,不能保证在提交事务时会发生这种情况。例如。在计算某些统计数据时,您不能在同一事务中使用它们,因为 Eclipselink 可以在事务已经完成时进行处理。

      您必须使用您使用的实体才能创建 em.persist()。如果您执行数据库查询。需要 Eclipselink 来刷新实体,因为查询可能不正确。但是在尝试扩展应用程序时,使用 em.flush() 会导致一些非常糟糕的性能问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-12
        • 1970-01-01
        • 2015-07-04
        • 1970-01-01
        相关资源
        最近更新 更多