意外的分离实体扩展的背景下持续(Unexpected detached entities with

2019-09-23 07:08发布

我试图通过使用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使用有效名称(这种情况继续下去的项目数据库)。
  • 打电话的addItem与“无效”的名称,这将引发约束例外。
  • 打电话的addItem使用有效名称(这会导致一个分离的实体错误就行了em.persist(child)

我不明白的是如何/为什么我结束了与分离的实体。 在实际的代码,我会进行一些请求/状态验证,修改前的状态(所以没有任何理由,我可以看到已经被拆下)。

如果我删除调用sessionBean.getLock()然后问题消失(对象坚持正确)。 的锁方法的目的本质上是串行访问会话状态,但目前getLock()方法是空的,感觉这个问题可能与这样的事实,我打电话到状态bean抛出异常之前。

任何人能解释这是怎么回事,在我的实体结果上脱离/如果有一种方法,以避免它(理想在支持任何解释文档点我)?

虽然有可能的方式,我可以解决当前的问题,在所有访问状态bean之前执行验证,我很担心,一般情况下(有状态Bean已经在呼叫被访问后的任何异常被抛出)。 有没有被拆除,以便处理异常时,我不希望实体从扩展持久上下文中接受的策略?

Answer 1:

看起来这是预期的行为。 由于斯科特马洛的参考JPA规范,第3.3.2节。

事务回滚对于这两个事务范围和扩展的持久化上下文,事务回滚导致所有预先存在的托管实例并除去实例[31],以变得脱离。 各实例的状态将在在该事务回滚点的情况下的状态。 事务回滚通常会导致持久性上下文为处于不一致状态在回退点。 特别是,版本属性和生成的状态(例如,生成的主密钥)的状态可能是不一致的。 先前由持久性上下文(包括所以在该事务中的持久性的新实例)进行管理,因此可以不以相同的方式作为其他分离的可重复使用的实例的对象,例如,它们可传递给合并操作时失败。[32 ]

所以,当事务回滚,并通过调用出来的一个sessionBean我涉及它在交易中涉及的活动事务实体分离。

解决此问题的方法似乎是装饰用可接受的例外@AppicationException注解。 这标志着异常作为非致命并防止交易被回滚。 这种方法在一些详细描述大卫Blevin 。



文章来源: Unexpected detached entities with extended persistent context