我试图通过使用 EXTENDED_PERSISTENT_CONTEXT 来维护多个调用的状态。我的理解是托管实体不会在调用之间分离,但是在我之前抛出验证错误之后,我不断收到与调用中分离实体相关的错误。状态在有状态会话 bean 中维护:
@Named(SessionFacadeBean.SEAM_NAME)
@SessionScoped
@Stateful
@LocalBean
@AccessTimeout(value = 10, unit = TimeUnit.SECONDS)
public class SessionFacadeBean implements Serializable
{
public static final String SEAM_NAME = "sessionCacheBean";
@PersistenceContext(unitName = GlobalParameters.BACKEND_CODE_PERSISTENCE_CONTEXT_NAME, type = PersistenceContextType.EXTENDED)
private EntityManager em;
private ParentOne sessionData;
public synchronized ParentOne getSessionData() {
if(sessionData == null) {
sessionData = new ChildTwo();
}
return sessionData;
}
public boolean getLock() {
return true;
}
public void clearLock() {
}
// Other stuff I don’t ‘think’ is relevant.
}
(简化的)状态正在使用休眠进行存储。它由三个类(一个父类和两个子类,其中一个包含子类列表)组成:
@XmlRootElement(name = XMLConstants.COMPONENT_ELEMENT_NAME_IN_XML)
@XmlAccessorType(XmlAccessType.NONE)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "Class", length = 50)
@Entity
public class ParentOne
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@XmlElement(name = "ID")
private Long iD;
@XmlElement(name = "name")
protected String friendlyName = "";
}
@XmlRootElement(name = XMLConstants.COMPONENT_ELEMENT_NAME_IN_XML)
@XmlAccessorType(XmlAccessType.NONE)
@Entity
public class ChildOne extends ParentOne
{
public ChildOne(String name, ParentOne child) {
super(name);
myChild = child;
}
@ManyToOne(cascade = CascadeType.ALL)
protected ParentOne myChild;
}
@XmlRootElement(name = XMLConstants.COMPONENT_ELEMENT_NAME_IN_XML)
@XmlAccessorType(XmlAccessType.NONE)
@Entity
public class ChildTwo extends ParentOne
{
public ChildTwo() {
super(“common”);
}
}
我正在从无状态 bean 访问有状态 bean,如下所示:
@Stateless
@LocalBean
@Path("/")
public class MyService
{
@PersistenceContext(unitName = GlobalParameters.BACKEND_CODE_PERSISTENCE_CONTEXT_NAME)
private EntityManager em;
@Inject
private SessionFacadeBean sessionBean;
@POST
@Path("/create/item")
@ValidateRequest
public ComponentShortSummary addItem(@Form NewItemForm itemForm)
{
if(sessionBean.getLock()) {
try {
if(itemForm.getName().equals("INVALID") == true) {
throw new ConstraintViolationException("Failed", new HashSet<ConstraintViolation<?>>());
}
ChildOne child = new ChildOne(itemForm.getName(), sessionBean.getSessionData());
em.persist(child);
return null;
}
finally {
sessionBean.clearLock();
}
} else {
return null;
}
}
}
为了重现该问题,我执行以下顺序:
- 使用有效名称调用 addItem(这会将项目保存到数据库中)。
- 使用名称“INVALID”调用 addItem,这会引发约束异常。
- 使用有效名称调用 addItem(这会导致在
em.persist(child)
.
我不明白的是我如何/为什么最终得到分离的实体。在实际代码中,我会在修改状态之前执行一些请求/状态验证(因此我没有理由看到状态已被分离)。
如果我删除对的调用,sessionBean.getLock()
那么问题就会消失(对象正确存在)。锁定方法的目的本质上是序列化对会话状态的访问,但是目前该getLock()
方法是空的,感觉问题可能与我在抛出异常之前调用有状态 bean 的事实有关。
任何人都可以解释导致我的实体变得分离的原因/如果有办法避免它(最好将我指向任何支持解释的文档)?
虽然可能有一些方法可以解决当前问题,在访问有状态 bean 之前执行验证,但我担心一般情况(在调用中访问有状态 bean 后抛出任何异常)。当我不希望扩展持久上下文中的实体被分离时,是否有一种公认的处理异常的策略?