6

我认为 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。

4

2 回答 2

2

您所经历的一切都是根据规范。当事务存在时,持久性上下文仍然存在(并且实体保持连接)。因此,在扩展的持久性上下文和NOT_SUPPORTED事务中,通过调用 find 方法检索到的对象是分离的。-此外,如果您的Customer对象具有惰性关系并且您尝试访问它们,那么您很可能会遇到运行时异常。-

现在,为什么该merge方法就可以了?好吧,首先请记住,它merge返回一个托管实体并将客户附加到持久性上下文。

其次,您有一个持久性上下文,因此,在您调用带注释的方法EXTENDED之前,它不会去更新数据库。@Remove当这个电话到达时,你可能会得到一个TransactionRequiredException.

编辑 1 ------------------------------------------------ --------------------------------

根据您的评论:

  • find不需要在事务中,但是,如果您想要托管对象,则必须有一个。

  • 该段落是关于 EM 生命周期(第 3.3 节),在这种情况下,试图解释在事务范围 bean 的方法结束时,实体将被分离,但是,在扩展 EM 的情况下,实体将保持连接。

  • 有2个有见地的段落:

  1. 当使用具有扩展持久性上下文的 EM 时,无论事务是否处于活动状态,都可以调用持久化、删除、合并和刷新操作。当扩展持久性上下文在事务中登记并且事务提交时,这些操作的效果将提交给数据库。

  2. 当有状态会话 bean 的 @Remove 方法完成时(或者有状态会话 bean 实例被销毁),容器将关闭持久性上下文。

  • 看起来您最初在问题中省略的方法@TransactionAttribute(REQUIRES_NEW)是成功发生合并的地方。这就是为什么你没有例外。

编辑 2 ------------------------------------------------ --------------------------------

经过一番测试,GF4有bug,已经报> https://java.net/jira/browse/GLASSFISH-20968

编辑 3 ------------------------------------------------ ---------------------------------

2014 年 5 月 20 日:该错误已标记为:必须修复Glassfish 4.0.1。

于 2014-01-28T19:43:56.370 回答
0

根据 Checkus 的说法,这似乎是 GF4 中的一个错误:https ://java.net/jira/browse/GLASSFISH-20968

于 2014-02-03T11:55:59.207 回答