使用Extended PersistentContext时,实体不受管理

时间:2016-03-16 17:28:44

标签: jpa java-ee persistence

环境:

  JDK 1.8
  WildFly 10.0.0.Final

我关注@Stateful bean

@Stateful
@SessionScoped
@Local(CdiStatefulEmployeeService.class)
public class CdiStatefulEmployeeBean implements CdiStatefulEmployeeService {

  @PersistenceContext(name = "employees", type = PersistenceContextType.EXTENDED)
  EntityManager extendedEm;

  private Employee cached;

  @Override
  public String service() {
    cached = extendedEm.find(Employee.class, 499983);
    return cached.getFirstName();
  }

  @Override
  public String updateEntity() {
    cached.setFirstName("Uri2");
    //extendedEm.flush();   -- Line 1
    return cached.getFirstName();
  }
}

并关注Servlet客户端

@WebServlet("/atInjectedStatefulEjbClient")
public class AtInjectedStatefulEjbClient extends HttpServlet {

  @Inject
  CdiStatefulEmployeeService statefulBean;

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    HttpSession session = req.getSession(true);
    resp.setContentType("text/plain");

    PrintWriter pw = resp.getWriter();

    pw.println(statefulBean.service());
    pw.println();
    pw.println(statefulBean.updateEntity());

    session.invalidate();
    pw.flush();
    pw.close();
  }
}

观察:调用bean.updateEntity()方法不会自动保存更改,即将名字设置为“Uri2”。

问题:在扩展持久化上下文的情况下,是否跨越调用管理实体?

调用flush()(即取消注释第1行)也没有效果。基本上,实体不在updateEntity()调用中进行管理。我觉得这很奇怪。有什么想法吗?

UPDATE:

仅排除可能性,尝试使用相同的代码,但使用以下

  • 没有@SessionScoped
  • 没有@Inject(替换为servlet doGet()内的JDNI查找)
  • 在bean中添加了@Remove方法
  • 调用其他2个方法后,让servlet doGet()调用@Remove

结果:同样的问题。第一次服务呼叫后不管理实体

Rakesh

3 个答案:

答案 0 :(得分:0)

假设在service显示所描述的行为之前调用了updateEntity方法:service方法的事务属性是默认的,这意味着,正如您在{{1该事务在updateEntity调用结束时提交。此提交使service实体不受管理。我建议使用cached注释service方法,该方法应保持@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)实体的管理,随后调用cached查找管理实体。

通常,对于扩展的持久性上下文,Facade EJB类使用updateEntity进行注释,并且只有应该提交的EJB方法才能获得不同的事务属性(请参阅文章Domain-driven design with Java EE 6)。 / p>

答案 1 :(得分:0)

永远不要将STATEFUL(会话相关)bean注入servlet(许多用户使用=多个会话)。如果使用CMT,则在调用@Remove标记方法后将执行事务提交。它在哪里?它可以是空的,但它对有状态的bean很重要。

但这将是一个可行的解决方案:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
  <h:head>
    <title>Facelet Title</title>
  </h:head>
  <h:body>
    <h:form>
    <h:inputText value="#{employeeMB.emplyeeName}"/>
    <h:commandButton value="Submit" action="#{employeeMB.onSubmit}"/>
    </h:form>
  </h:body>
</html>

@ManagedBean
@SessionScoped
@Getter
@Setter
public class EmployeeMB
{
  private String employeeName;

  @EJB
  private EmployeeSB employeeSB;

  public void onSubmit()
  {
    employeeSB.persist( employeeName );
    employeeName = "";
  }
}

@Stateless
@LocalBean
public class EmployeeSB
{
  @PersistenceContext
  private EntityManager em;

  public void persist( String employeeName_ )
  {
    Employee e = new Employee();
    e.setName( employeeName_ );
    em.persist( e );
  }
}

答案 2 :(得分:0)

似乎是WildFly中的一个错误。所有文档(规范,书籍等)都指出扩展上下文意味着在事务结束时防止实体脱离。

提起Wildfly问题:https://issues.jboss.org/browse/WFLY-6383