同一表对应多JPA实体致读取不一致,如何获取最新数据?
同表映射多JPA实体后更新读取不一致的解决方法
可行解决方案
1. 刷新并清空持久化上下文
在读取Person2之前,先把Person1的变更同步到数据库,再清空当前事务的持久化上下文,确保查询Person2时从数据库重新加载最新数据:
@Autowired private EntityManager entityManager; @Transactional public void doSomething() { Person1 person1 = person1Repo.findById(1L); person1.setName("tom1"); person1Repo.save(person1); // 同步变更到数据库,清空缓存 entityManager.flush(); entityManager.clear(); Person2 person2 = person2Repo.getById(1L); // 此时能获取到更新后的tom1 }
2. 使用saveAndFlush + findById组合
saveAndFlush()会直接把变更同步到数据库,而findById()相比getById()会优先执行数据库查询(如果缓存中没有对应Person2实例的话):
@Transactional public void doSomething() { Person1 person1 = person1Repo.findById(1L); person1.setName("tom1"); person1Repo.saveAndFlush(person1); // 立即同步变更到数据库 Person2 person2 = person2Repo.findById(1L).orElse(null); // 读取最新数据 }
3. 重构代码:只保留一个实体类(最优方案)
同一个数据库表映射多个JPA实体本身违反JPA设计规范,会引发缓存不一致、映射逻辑混乱等问题。最彻底的解决方式是删除Person1或Person2,仅保留一个Person实体类,所有对该表的操作都基于这个实体完成。
问题原因
这是JPA一级缓存(持久化上下文)的特性导致的:
- 每个实体类在持久化上下文中拥有独立的缓存空间,Person1和Person2作为不同类,缓存完全隔离。
getById()默认返回代理对象,优先从一级缓存取数据,不会触发数据库查询。- 事务内的
save()操作仅将变更写入缓存,不会立即同步到数据库;即使同步后,如果缓存中有旧的Person2实例,依然会读取旧值。
内容的提问来源于stack exchange,提问作者Nero
相关产品推荐
相关产品推荐

