具有扩展的持久性上下文的意外分离实体 [英] Unexpected detached entities with extended persistent context

查看:89
本文介绍了具有扩展的持久性上下文的意外分离实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用EXTENDED_PERSISTENT_CONTEXT来维护多个呼叫的状态.我的理解是,托管实体不会在调用之间分离,但是在先前引发验证错误之后,我不断收到与调用中分离的实体有关的错误.状态是在有状态会话Bean中维护的:

I'm trying to maintain state across multiple calls by using an EXTENDED_PERSISTENT_CONTEXT. My understanding is that managed entities will not detach between calls however I keep getting errors related to detached entities in calls after I have previously thrown validation errors. The state is being maintained in a stateful session 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.
}

(简化的)状态是使用休眠方式存储的.它由三个类组成(一个父级和两个孩子,其中一个包含一个孩子列表):

The (simplified) state is being stored using hibernate. It consists of three classes (a parent, and two children, one of which contains a list of children):

@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,如下所示:

I’m accessing the stateful bean from a stateless bean like so:

@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;
        }
    }
}

为重现该问题,我执行以下顺序:

To reproduce the problem, I perform the following sequence:

  • 使用有效名称调用addItem(这会将项目持久保存到数据库中).
  • 使用名称"INVALID"调用addItem,这将引发约束异常.
  • 使用有效名称调用addItem(这会导致在em.persist(child)行上出现分离的实体错误.
  • Call addItem with a valid name (this persists the item to the database).
  • Call addItem with a name ‘INVALID’, this throws the constraint exception.
  • Call addItem with a valid name (this results in a detached entity error on the line em.persist(child).

我不明白的是为什么/为什么以分离的实体结束.在真实的代码中,在修改状态之前,我将执行一些请求/状态验证(因此,没有理由可以看到状态已被分离).

What I don’t understand is how/why I’m ending up with detached entities. In the real code, I would be performing some request / state validation, before modifying the state (so there is no reason that I can see for the state to have been detached).

如果我取消对sessionBean.getLock()的调用,那么问题就消失了(这些对象正确存在).锁定方法的目的本质上是序列化对会话状态的访问,但是当前getLock()方法为空,感觉问题可能与我在引发异常之前调用有状态Bean的事实有关

If I remove the call to sessionBean.getLock() then the problem goes away (the objects persist correctly). The purpose of the lock methods is essentially to serialize access to the session state, however currently the getLock() method is empty, it feels like the problem might be related to the fact that I’m calling into the stateful bean before throwing the exception.

任何人都可以解释发生了什么事,这导致我的实体变得超脱/是否有避免的方法(理想情况下,请我指向支持该解释的任何文档)?

Can anybody explain what’s going on that results in my entities becoming detached / if there is a way to avoid it (and ideally point me at any documentation that supports the explanation)?

虽然我可能有一些方法可以解决当前问题,但在访问有状态Bean之前先执行验证,但我担心一般情况(在访问有状态Bean之后会抛出任何异常)称呼).当我不希望从扩展的持久性上下文中分离实体时,是否存在一种可接受的策略来处理异常?

Whilst there are probably ways that I can work around the current issue, performing validation before accessing the stateful bean at all, I’m concerned about the general case (where any exception is thrown after the stateful bean has been accessed in the call). Is there an accepted strategy for dealing with exceptions when I don’t want the entities from the extended persistent context to be detached?

推荐答案

这似乎是预期的行为.感谢 Scott Marlow 对JPA规范的引用,第3.3.2节.

It looks like this is expected behaviour. Thanks to Scott Marlow's reference to the JPA spec, section 3.3.2.

事务回滚 适用于交易范围和扩展范围 持久性上下文,事务回滚会导致所有先前存在的 受管实例和已删除实例[31]成为分离的.这 实例的状态将是实例在以下位置的状态: 交易被回滚了.交易回滚通常 导致持久化上下文处于不一致状态 回滚点.特别是版本属性的状态和 生成的状态(例如生成的主键)可能不一致. 以前由持久性上下文管理的实例 (包括在其中保持不变的新实例 交易)因此可能无法以与其他方式相同的方式重复使用 分离的对象-例如,它们在传递到合并时可能会失败 操作.[32]

Transaction Rollback For both transaction-scoped and extended persistence contexts, transaction rollback causes all pre-existing managed instances and removed instances[31] to become detached. The instances’ state will be the state of the instances at the point at which the transaction was rolled back. Transaction rollback typically causes the persistence context to be in an inconsistent state at the point of rollback. In particular, the state of version attributes and generated state (e.g., generated primary keys) may be inconsistent. Instances that were formerly managed by the persistence context (including new instances that were made persistent in that transaction) may therefore not be reusable in the same manner as other detached objects—for example, they may fail when passed to the merge operation.[32]

因此,回滚事务时,将活动事务中涉及的实体分离,并通过调出sessionBean来使我将其包含在事务中.

So, entities that are involved in the active transaction are detached when the transaction is rolled back and by calling out to the sessionBean I am involving it in the transaction.

解决此问题的一种方法似乎是使用@AppicationException批注装饰可接受的异常.这将异常标记为非致命异常,并阻止了事务回滚. David Blevin .

One way around this appears to be to decorate acceptable exceptions with the @AppicationException annotation. This marks the exception as non-fatal and prevents the transaction from being rolled back. This approach is described in some detail by David Blevin.

这篇关于具有扩展的持久性上下文的意外分离实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆