2012-03-21 89 views
4

因此,我在此类EJB级注释了@TransactionAttribute(TransactionAttributeType.REQUIRED),以便每个方法都应该在事务中执行,除非我重写此行为,当事务提交时,数据将被刷新, 对?到现在为止还挺好。 所以现在我有一个public User find(String email)方法,用@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)注解,所以这个方法不在事务中执行,因为它只提取数据。了解EJB中的JTA:不刷新

好的,所以我正在测试我的应用程序,并且我有一个引导程序方法,使用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> 

也不例外,除了一说,没有实体已经发现,当我搜索,在这之后,刷新缓存到数据库中提出。

回答

3

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

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

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

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

+0

这是“NEVER”属性,NOT_SUPPORTED挂起一个事务(如果处于活动状态)或者如果不活动,它将执行事务外的方法。它使该方法非事务性。如果在事务中调用该方法,它不会引发异常。 – arg20 2012-03-23 11:26:41

+1

那么如果你不使用,你会得到异常吗? – Chris 2012-03-23 13:28:30

+0

@Chris我得到一个异常是!它说:'javax.ejb.EJBException:EJB不能在全局事务中被调用,你是对的,事务没有被提交,insted一个“全局”事务被启动。为什么?这是一种优化?我从RequestScoped CDI bean调用,该bean是非事务性的。我不知道发生了什么事 – arg20 2012-03-23 15:18:26

1

添加它将显示执行语句的时间以及事务提交的时间。由于NOT_SUPPORTED暂停交易,因此如果先前的交易已提交,则只能“查找”数据。很可能你的保存方法被封装在你的查找方法暂停的大事务中。 Flush不会改变这一点,因为这些数据仍然是事务隔离的。

尝试使用REQUIRES_NEW将保存方法放在自己的事务中,当完成时提交。

0

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

您必须使用您为了制作em.persist()而使用的实体。如果你执行数据库查询。 Eclipselink需要刷新实体,因为查询可能不正确。但是,当使用em.flush()来扩展应用程序时,会导致一些非常难看的性能问题。