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();
}
问题:
- 据我所知,设置托管对象的属性足以将更改传播到数据库。但我想立即刷新更改。我的方法是额外调用update是合适的解决方案还是调用setter就足以在DB中立即进行更改?我所说的额外更新是指
documentDAO.updateDocument(doc); // IS IT NECESSARY??
- JPA如何将托管对象存储在某些内部数据结构中,或者只是将它们保存在
Document doc;
之类的引用中?内部结构最有可能使重复/sameID托管对象不可能,引用最有可能使具有相同id和其他属性的多个托管对象成为可能李> merge
如何在内部工作-尝试在内部存储中查找具有相同ID的托管对象,并在检测时刷新其字段或仅更新数据库李>- 如果内部存储确实存在(很可能是持久性上下文,更进一步的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 楼答案
首先,您希望在单个事务服务方法中注册读和写操作:
因此,此代码应该驻留在服务端,而不是web控制器中
这只适用于托管实体,只要持久性上下文仍然打开。这就是为什么您需要一个事务服务方法
JPA一级缓存只是按原样存储实体,不使用任何其他数据表示。在持久性上下文中,您可以有并且只能有一个实体表示(类和标识符)。在JPA持久性上下文中,托管的entity equality is the same with entity identity
merge
操作对reattaching detached entities有意义。托管实体状态在刷新期间自动与数据库同步。{a3}负责这个PersistenceContext是会话级缓存。托管对象始终具有标识符和关联的数据库行
在相同的持久性上下文范围内,这是不可能发生的。如果通过查询加载实体,该实体将在一级缓存中获取缓存。如果您尝试使用另一个查询或EntityManager再次加载它。find()您仍将获得已缓存的相同对象引用
如果第一个查询是针对持久性上下文进行的,而第二个查询/查找是针对第二个持久性上下文进行的,那么每个持久性上下文都必须缓存其自身版本的被查询实体
这不可能发生。持久性上下文始终保持实体对象的完整性