有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java为什么JPA实体在每个偶数查询上选择结果更改?

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

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

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

文件道。getDocuments看起来像

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

在另一个控制器中,我还提取文档并使用

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

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. 据我所知,设置托管对象的属性足以将更改传播到数据库。但我想立即刷新更改。我的方法是额外调用update是合适的解决方案还是调用setter就足以在DB中立即进行更改?我所说的额外更新是指documentDAO.updateDocument(doc); // IS IT NECESSARY??
  2. JPA如何将托管对象存储在某些内部数据结构中,或者只是将它们保存在Document doc;之类的引用中?内部结构最有可能使重复/sameID托管对象不可能,引用最有可能使具有相同id和其他属性的多个托管对象成为可能
  3. merge如何在内部工作-尝试在内部存储中查找具有相同ID的托管对象,并在检测时刷新其字段或仅更新数据库
  4. 如果内部存储确实存在(很可能是持久性上下文,更进一步的PC),那么DistInquiresh托管对象的标准是什么@Id注释了hibernate模型的字段

我的主要问题是entityManager.createQuery("from Document");的不同结果

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

我怀疑首先选择所有查询返回isSigned=false的实体,并将它们放在PC上,然后用户执行一些操作,获取实体byID,设置isSigned=true,并且刚刚提取的实体与PC中已经显示的实体冲突。第一个对象的isSigned=false,second已isSigned=true且PC混淆,并轮流返回不同的托管对象但这怎么可能呢在我看来,PC有一种机制,通过为每个唯一的id只保留一个托管对象,不允许出现这种混淆不清的情况


共 (1) 个答案

  1. # 1 楼答案

    首先,您希望在单个事务服务方法中注册读和写操作:

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

    因此,此代码应该驻留在服务端,而不是web控制器中

    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??

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

    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.

    JPA一级缓存只是按原样存储实体,不使用任何其他数据表示。在持久性上下文中,您可以有并且只能有一个实体表示(类和标识符)。在JPA持久性上下文中,托管的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?

    merge操作对reattaching detached entities有意义。托管实体状态在刷新期间自动与数据库同步。{a3}负责这个

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

    PersistenceContext是会话级缓存。托管对象始终具有标识符和关联的数据库行

    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.

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

    如果第一个查询是针对持久性上下文进行的,而第二个查询/查找是针对第二个持久性上下文进行的,那么每个持久性上下文都必须缓存其自身版本的被查询实体

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

    这不可能发生。持久性上下文始终保持实体对象的完整性