Spring Boot切换JPA为EclipseLink后实体未调用save自动更新问题咨询
问题成因
该行为差异不属于EclipseLink配置错误,是两款JPA实现的默认机制差异,核心原因如下:
- Spring Boot Web项目默认开启
OpenEntityManagerInViewInterceptor,整个HTTP请求生命周期内共享同一个EntityManager实例,updatePerson方法中通过Repository查询得到的Person实体始终处于托管状态,和当前EntityManager绑定。 - EclipseLink默认脏数据追踪策略:只要托管实体发生变更,当前
EntityManager只要关联到任意事务(包括后续调用的标注@Transactional的方法、Spring Data JPA Repository默认自带的事务),事务提交前会自动将所有未持久化的脏变更刷新到数据库,无需显式调用save/merge方法。 - Hibernate默认策略和EclipseLink不同:事务外修改的托管实体,后续新开事务默认不会主动刷新之前的脏变更,必须显式触发
save/flush才会同步变更。
对齐Hibernate行为的解决方案
可按需选择以下任意一种方案调整:
方案1:修改EclipseLink配置(推荐)
在EclipselinkJpaConfiguration的getVendorProperties方法中追加以下配置即可:
@Override protected Map<String, Object> getVendorProperties() { Map<String, Object> map = new HashMap<>(); map.put(PersistenceUnitProperties.WEAVING, "false"); // 新增以下配置 map.put(PersistenceUnitProperties.PERSISTENCE_CONTEXT_CLOSE_ON_COMMIT, "true"); map.put(PersistenceUnitProperties.FLUSH_MODE, "COMMIT"); return map; }
PERSISTENCE_CONTEXT_CLOSE_ON_COMMIT设为true后,事务提交后会自动将所有关联的托管实体转为游离态,跨事务的实体变更不会再被自动同步。
方案2:关闭OpenEntityManagerInView
如果没有在视图层懒加载实体的需求,直接在application.properties中添加配置关闭即可:
spring.jpa.open-in-view=false
关闭后每次Repository方法调用结束就会关闭EntityManager,查询得到的实体直接为游离态,修改后必须显式调用save才会同步到数据库。
方案3:业务代码显式剥离实体
如果不需要修改后的实体被持久化,查询到实体后显式调用entityManager.detach(person)将其转为游离态即可:
@PersistenceContext private EntityManager entityManager; public Person updatePerson(Long id) { Optional<Person> personOP = personRepository.findById(id); if (personOP.isPresent()) { Person person = personOP.get(); person.setFirstName("Update Name"); // 显式剥离实体,变更不会被追踪 entityManager.detach(person); } return null; }
内容的提问来源于stack exchange,提问作者rlaxodus
相关产品推荐
相关产品推荐

