我们在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
firstName
和lastName
等大多数属性都使用@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。 / p>
对于“大”模型,现在似乎在仍然加载相关对象的过程中提交了一个事务,因为我们得到了ERROR: null value in column "age" violates not-null constraint
。由于我们使用JTA容器管理的事务并且没有将@TransactionAttribute
设置为默认REQUIRED
以外的其他事项,因此我们不直接控制事务,也不知道这里出了什么问题。
在提交之前是否有一定数量的“工作单位”可以被忽略?我们加载相关对象是错误的吗?我们还犯了其他一些重大错误吗?
一旦省略nullable=false
约束,一切正常......
答案 0 :(得分:4)
您的实体可能在查询发生时自动刷新。根据{{3}}的JavaDocs:
在事务中执行查询时,如果在Query对象上设置了
FlushModeType.AUTO
,或者持久化上下文的刷新模式设置为AUTO
(默认值)并且尚未为Query对象指定刷新模式设置,持久性提供程序负责确保所有更新到持久性上下文中的所有实体的状态,这可能会影响查询结果对查询处理可见。持久性提供程序实现可以通过将这些实体刷新到数据库或通过其他方式实现。如果设置了FlushModeType.COMMIT
,则未指定在查询时对持久性上下文中的实体所做的更新的效果。
基本上,如果您进行查询,并且任何未提交的实体(尚未设置其所有成员)都有资格成为该查询的结果,那么持久性实现必须将它们刷新到数据库(或执行具有相同效果的操作),从而导致抛出异常,因为可空约束无效。这对我来说似乎有点不直观。如果我们的申请中没有遇到过类似的问题,我就不会知道。
听起来您只想使用FlushModeType
或EntityManager.setFlushMode()
将刷新模式设置为COMMIT
。