[英]JPA Entity found by find in a stateful ejb extended is not managed
我以为由em.find找到的实体是由em自动管理的,甚至进行了事务处理,但是下面的此类似乎表明了相反的情况。 我错了吗?或者那堂课有什么错误?
@Stateful
@TransactionAttribute(NOT_SUPPORTED)
public class CustomerGateway {
@PersistenceContext(unitName = "customersPU", type = EXTENDED)
private EntityManager em;
private Customer customer;
public Customer find(Long id) {
// customer is not managed!
this.customer = em.find(Customer.class, id);
// Print false!
System.out.println("Method find: " + em.contains(customer));
// Print false too (2 is the id of an entity)!
System.out.println("Method find: " + em.contains(em.find(Customer.class, 2L));
// A workaround
customer = em.merge(customer);
// Print true.
System.out.println("Method find after merge: " + em.contains(customer));
return this.customer;
}
编辑1:实体的代码
@Entity
@NamedQuery(name = "Customer.all", query = "select c from Customer c")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
public Customer() {
}
public Customer(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Customer)) {
return false;
}
Customer other = (Customer) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "entity.Customer[ id=" + id + " ]";
}
}
有状态EJB的代码:
@Stateful
@TransactionAttribute(NOT_SUPPORTED)
public class CustomerGateway {
@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager em;
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void create(Customer customer) {
em.persist(customer);
this.customer = customer;
}
public Customer find(Long id) {
this.customer = em.find(Customer.class, id);
System.out.println("customer managed ? " + em.contains(this.customer));
// Workaround :
// this.customer = em.merge(customer);
return customer;
}
public void remove(Long id) {
Customer cust = em.getReference(Customer.class, id);
em.remove(cust);
}
@TransactionAttribute(REQUIRES_NEW)
public void save() {
}
public List<Customer> findAllCustomers() {
Query query = em.createNamedQuery("Customer.all");
return query.getResultList();
}
@Remove
public void close() {
}
}
我使用NetBeans 7.4,GlassFish 4.0,EJB 3.2,Java DB。
您所经历的一切都符合规范。 事务存在时,持久性上下文保留(实体保持连接状态)。 因此,在扩展的持久性上下文和NOT_SUPPORTED
事务中,通过调用find方法检索的对象将被分离。 -此外,如果您的Customer
对象具有惰性关系,并且您尝试访问它们,则很有可能会收到运行时异常。
现在,为什么merge
方法还可以? 好吧,首先请记住, merge
返回一个受管实体,并将客户附加到持久性上下文。
其次,您具有EXTENDED
持久性上下文,因此,除非调用@Remove
注释的方法,否则它将不会更新数据库。 当此调用到达时,您可能会收到一个TransactionRequiredException
。
编辑1 ------------------------------------------------ --------------------------------
根据您的评论:
find
不需要在事务中,但是,如果要托管对象,则必须有一个。
本段是关于EM的生命周期(第3.3节),在这种情况下,它试图解释在事务范围的bean的方法结束时,实体将被分离,但是在扩展EM的情况下,实体将保持连接。
有2个有见地的段落:
当使用具有扩展的持久性上下文的EM时,无论事务是否处于活动状态,都可以调用持久,删除,合并和刷新操作。 当在事务中征用扩展的持久性上下文并且提交事务时,这些操作的效果将提交给数据库。
当有状态会话Bean的@Remove方法完成时(否则,有状态会话Bean实例被破坏),容器将关闭持久性上下文。
@TransactionAttribute(REQUIRES_NEW)
忽略的方法是成功进行合并的地方。 这就是为什么你没有例外。 编辑2 ------------------------------------------------ --------------------------------
经过一些测试,GF4存在一个错误,并已报告> https://java.net/jira/browse/GLASSFISH-20968
编辑3 ------------------------------------------------ ---------------------------------
2014年5月20日:该错误已标记为:Glassfish 4.0.1 必须修复 。
根据Checkus的说法,这似乎是GF4中的错误: https ://java.net/jira/browse/GLASSFISH-20968
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.