【问题标题】:JTA transactions committing too early, fails when using constraintsJTA 事务提交过早,使用约束时失败
【发布时间】:2011-05-12 22:05:41
【问题描述】:

我们有一个在 Glassfish 3.1 中运行的 Java EE 应用程序,我们的 JPA 模型(使用 EclipseLink)组织如下:

Customer
 -> String firstName
 -> String lastName
 -> Address adress
 -> List<Attribute> attributes
 -> Int age

Address
-> String street
-> Int zip
-> String city

Attribute
 -> String code
 -> String name

firstNamelastName 等大多数属性都使用@Column(nullable=false) 进行注释。现在我们这样做:

@Stateless
public class CustomerController {

  @PersistenceContext(unitName = "CustomerService")
  private EntityManager em;

  @EJB
  private AttributeController attributeController;

  public String createCustomer() {
    Customer customer = new Customer();
    customer.firstName = "Hans";
    customer.lastName = "Peter";

    customer.address = new Address();
    customer.adress.street = ...

    customer.attributes = new ArrayList<Attribute>();
    customer.attributes.add(attributeController.getByCode("B"));
    customer.attributes.add(attributeController.getByCode("T"));

    customer.age = 27;

    em.persist(customer);
  }
}

这适用于像上面这样的小类,但我们现在引入了更多与客户相关的对象,例如带有 @OneToMany 的属性,并从其他 @EJBs 加载,例如 attributeController。

对于“大”模型,现在似乎在加载相关对象的过程中提交了一个事务,因为我们得到了一个ERROR: null value in column "age" violates not-null constraint。由于我们使用 JTA 容器管理事务并且没有将 @TransactionAttribute 设置为默认 REQUIRED 以外的其他值,因此我们不直接控制事务并且不知道这里出了什么问题。

在提交之前是否有一定数量的“工作单元”可以公开?我们是否加载了错误的相关对象?我们是否犯了其他重大错误?

只要我们省略了nullable=false 约束,一切正常...

【问题讨论】:

    标签: jpa transactions ejb constraints jta


    【解决方案1】:

    当查询发生时,您的实体可能会自动刷新。根据FlushModeType的JavaDocs:

    在事务中执行查询时,如果在 Query 对象上设置了 FlushModeType.AUTO,或者持久性上下文的刷新模式设置为 AUTO(默认值),并且刷新尚未为 Query 对象指定模式设置,持久性提供程序负责确保对持久性上下文中所有实体的状态的所有更新可能会影响查询结果 对查询的处理是可见的。持久性提供程序实现可以通过将这些实体刷新到数据库 或通过其他方式来实现。如果设置了FlushModeType.COMMIT,则未指定对持久化上下文中的实体进行的更新对查询的影响。

    基本上,如果您进行查询,并且您的任何未提交的实体(尚未设置所有成员)将有资格成为该查询的结果,那么持久性实现必须 em> 将它们刷新到数据库(或执行具有等效效果的操作),从而导致抛出异常,因为可空约束无效。这对我来说似乎也有点不直观。如果我们没有在我们的应用程序中遇到非常相似的问题,我就不会知道它。

    听起来您只想使用EntityManager.setFlushMode()Query.setFlushMode() 将刷新模式设置为COMMIT

    【讨论】:

    • 谢谢!这解决了问题。但是我现在仍然在问自己为什么 AUTO 是默认值?在我看来,这完全消除了在这种情况下使用事务。我应该能够在事务中进行SELECTs,而无需在不注意的情况下提交事务。还有为什么COMMIT 的行为没有被定义为AUTO 的对立面,而是未指定?
    • 事务未提交。 EM 将实体刷新到数据库(在事务中),以便对数据库的查询(在同一事务中)可以找到这些对象。
    • 好的,这将以一致的方式解释行为!
    猜你喜欢
    • 2015-10-25
    • 1970-01-01
    • 2020-06-23
    • 2021-09-04
    • 2019-08-30
    • 1970-01-01
    • 2022-10-17
    • 2019-10-09
    • 2021-06-21
    相关资源
    最近更新 更多