为什么JPA实体在每个偶数查询中选择结果更改? [英] Why JPA Entity select result changes on each even query?

查看:122
本文介绍了为什么JPA实体在每个偶数查询中选择结果更改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当每次调用后相同的查询返回不同的结果时,我的问题与奇怪的读/选行为有关。我的情况描述如下:

我有以下代码,从DB返回文档列表

  @RequestMapping(value = {/ docs},method = RequestMethod.GET)
@ResponseBody
public ArrayList< Document> getMetaData(ModelMap modelMap){
return(ArrayList< Document>)documentDAO.getDocuments();
}

DocumentDAO.getDocuments看起来像

  public List< Document> getDocuments(){
Query query = entityManager.createQuery(from Document);
列表<文档> list = query.getResultList(); (Document doc:list)
System.out.println(doc.getName()++ doc.isSigned());
返回列表;





$ b

在其他控制器中,我也在提取Document和更改布尔属性

  Document doc = documentDAO.getDocumentById(id)
doc.setSigned(true);
documentDAO.updateDocument(doc); // 有必要吗??

getById和updateDocument如下:

  public Document getDocumentById(Long id){
return entityManager.find(Document.class,id);
}

@Transactional
public void updateDocument(Document document){
entityManager.merge(document);
entityManager.flush();

问题:


  1. 据我所知,设置托管对象的属性足以将更改传播到数据库。但我想立即刷新更改。我的方法是使用额外的更新调用是适当的解决方案,还是调用setter对于立即更改数据库就足够了?通过额外更新,我的意思是 documentDAO.updateDocument(doc); //它是必须的

  2. JPA如何存储托管对象 - 在某些内部数据结构中或者只是将它们保存在引用中,如 Document文档; ?内部结构很可能使得duplicate / sameID托管对象变得不可能,引用很有可能使多个具有相同id和其他属性的托管对象成为可能。 内部工作 - 尝试在内部存储中找到具有相同 ID 的托管对象,并在检测到时刷新其字段或仅更新DB ?如果内部存储真的存在(很可能这是持久性上下文,进一步的PC),那么区分受管理对象的标准是什么?
  3. hibernate模型的@Id注释字段

我的主要问题是 entityManager.createQuery(from Document);


$ b

System.out.println(doc.getName() ++ doc.isSigned()); 显示isSigned在奇数调用时为true,在偶数调用时为false。

我怀疑第一个全选查询返回带有isSigned = false的实体并将它们放到PC中,然后用户执行一些抓取实体byID的操作,设置isSigned =真正和刚刚提取的实体冲突已经在PC中呈现。 第一个对象有isSigned = false,第二个对象isSigned = true,PC混淆并返回不同的托管对象但它的可能性如何?在我看来,PC机制不允许这种令人困惑的模糊情境,因为每个唯一ID只保留一个托管对象。



 

@Transactional
public void signDocument(Long id){
Document doc = documentDAO.getDocumentById(id)
doc.setSigned(true);

$ / code>

所以这段代码应该驻留在服务端,而不是在你的web控制器中。



  1. 据我所知,设置托管对象的属性足以将更改传播到数据库。但我想立即刷新更改。
    我的方法是使用额外的更新调用是合适的解决方案还是
    调用setter对于立即更改数据库就足够了?额外
    更新我的意思是documentDAO.updateDocument(doc); //它是必须的


这只适用于托管实体,只要持久性上下文仍然是开放的。这就是为什么您需要事务性服务方法。



  1. JPA如何存储托管对象 - 在一些内部数据结构中,或者只是将它们保存在Document doc等引用中;?内部结构
    最有可能使得duplicate / sameID托管对象不可能,
    引用很可能使多个托管对象
    具有相同的id和其他属性。


JPA 1st级高速缓存只是简单地存储实体,它不使用任何其他数据表示。在一个持久性上下文中,你可以只有一个实体表示(类和标识符)。在JPA持久化上下文的上下文中,托管的实体相等与实体标识相同


内部合并的工作方式 - 尝试在内部存储中使用
相同的ID查找托管对象,并且在检测到,刷新
它是字段还是简单地更新数据库?


merge 操作对于重新附加分离的实体有意义。管理实体状态在刷新期间自动与数据库同步。 自动脏检查机制负责处理此问题。


  1. 如果内部存储真的存在(很可能这是持久性上下文,更进一步的PC),区分管理对象的标准是什么? @Id标注的hibernate模型字段?


  2. PersistenceContext是一个会话级缓存。被管理的对象总是有一个标识符和一个关联的数据库行。


    我怀疑第一个全选查询返回带有$ b $的实体b isSigned = false并将它们放到PC中,之后用户执行一些
    操作,抓取实体byID,设置isSigned = true,只需
    提取与PC中已经存在的实体冲突。


    在同一个持久性上下文范围中,这是不可能发生的。如果通过查询加载实体,则该实体会在第一级缓存中获取缓存。如果您尝试使用另一个查询或使用EntityManager.find()再次加载它,您仍将获得相同的对象引用,该对象引用已被缓存。



    如果第一个查询发生在持久性上下文中,并且第二个查询/查找将在第二个持久性上下文中发出,然后每个持久性上下文将不得不缓存它自己被查询的实体版本。



    < blockquote>

    第一个对象具有isSigned = false,第二个具有isSigned = true且PC
    混淆并返回不同的托管对象。但是,
    有多可能呢?


    这种情况不会发生。持久性上下文始终保持实体对象的完整性。


    My question is related to strange read/select behavior when same query returns different results after each call. Description of my situation is written below:

    I have the following code, returning list of documents from DB

    @RequestMapping(value={"/docs"}, method = RequestMethod.GET)
        @ResponseBody
        public ArrayList<Document> getMetaData(ModelMap modelMap) {
            return (ArrayList<Document>)documentDAO.getDocuments();
        }
    

    DocumentDAO.getDocuments looks like

    public List<Document> getDocuments() {
            Query query = entityManager.createQuery("from Document");
            List<Document> list = query.getResultList();
            for(Document doc:list) System.out.println(doc.getName()+" "+doc.isSigned());
            return list;
    }
    

    In other controller, I'm also extracting Document and changing boolean property with

     Document doc = documentDAO.getDocumentById(id)
     doc.setSigned(true);
     documentDAO.updateDocument(doc); // IS IT NECESSARY??
    

    getById and updateDocument are the following:

    public Document getDocumentById(Long id) {
            return entityManager.find(Document.class, id);
     }
    
    @Transactional
    public void updateDocument(Document document) {
        entityManager.merge(document);
        entityManager.flush();
    }
    

    Questions:

    1. As far as I know, setting property of managed object is enough to propagate changes to DB. But I want to flush changes immediately. Is my approach with extra call of update is appropriate solution or calling setter is enough for making immediate changes in DB? By extra update I mean documentDAO.updateDocument(doc); // IS IT NECESSARY??
    2. How JPA stores managed objects - in some internal data structure or simply keeps them in references like Document doc;? Internal structure most likely makes duplicate/sameID managed object impossible, references most likely makes possible to have multiple managed objects with same id and other properties.
    3. How merge works internally - tries to find managed object with the same ID in internal storage and, in the case of detecting, refreshes it's fields or simply updates DB?
    4. If internal storage really exists (most likely this is persistence context, futher PC), what is criteria for distinquish managed objects? @Id annotated field of hibernate model?

    My main problem is different results of entityManager.createQuery("from Document");

    System.out.println(doc.getName()+" "+doc.isSigned()); shows isSigned true on odd calls and false on even calls.

    I suspect that first select-all-query returns entities with isSigned=false and put them to PC, after that user performs some operation which grabs entity byID, sets isSigned=true and just extracted entity conflicts with already presented in PC. First object has isSigned=false, second has isSigned=true and PC confused and returns different managed objects in rotation. But how its possible? In my mind, PC has mechanisms to not allow such confusing ambigious situations by keeping only one managed object for each unique id.

    解决方案

    First of all you want to enrol both the read and the write in a single transactional service method:

    @Transactional
    public void signDocument(Long id) {
        Document doc = documentDAO.getDocumentById(id)
        doc.setSigned(true);
    }
    

    So this code should reside on the Service side, not in your web Controller.

    1. As far as I know, setting property of managed object is enough to propagate changes to DB. But I want to flush changes immediately. Is my approach with extra call of update is appropriate solution or calling setter is enough for making immediate changes in DB? By extra update I mean documentDAO.updateDocument(doc); // IS IT NECESSARY??

    This applies only to managed entities, as long as the Persistence Context is still open. That's why you need a transactional service method instead.

    1. How JPA stores managed objects - in some internal data structure or simply keeps them in references like Document doc;? Internal structure most likely makes duplicate/sameID managed object impossible, references most likely makes possible to have multiple managed objects with same id and other properties.

    The JPA 1st level cache simply stores entities as they are, it doesn't use any other data representation. In a Persistence Context you can have one and only one entity representation (Class and Identifier). In the context of a JPA Persistence Context, the managed entity equality is the same with entity identity.

    How merge works internally - tries to find managed object with the same ID in internal storage and, in the case of detecting, refreshes it's fields or simply updates DB?

    The merge operation makes sense for reattaching detached entities. A managed entity state is automatically synchronized with the database during flush-time. The automatic dirty checking mechanism takes care of this.

    1. If internal storage really exists (most likely this is persistence context, further PC), what is criteria for distinguish managed objects? @Id annotated field of hibernate model?

    The PersistenceContext is a session-level cache. The managed objects always have an identifier and an associated database row.

    I suspect that first select-all-query returns entities with isSigned=false and put them to PC, after that user performs some operation which grabs entity byID, sets isSigned=true and just extracted entity conflicts with already presented in PC.

    In the same Persistence Context scope this can't ever happen. If you load an entity through a query, the entity gets caches in the 1st level cache. If you try to load it again with another query or with the EntityManager.find() you will still get the same object reference, that's already cached.

    If the first query happens against a Persistence Context and the second query/find will be issued on a second Persistence Context, then each Persistence Context will have to cache its own version of the entities being queried.

    First object has isSigned=false, second has isSigned=true and PC confused and returns different managed objects in rotation. But how its possible?

    This can't happen. The Persistence Context always maintains entity object integrity.

    这篇关于为什么JPA实体在每个偶数查询中选择结果更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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