为了账号安全,请及时绑定邮箱和手机立即绑定

在 Hibernate 中同时使用 Query Api 和 Criteria Api 会导致问题

在 Hibernate 中同时使用 Query Api 和 Criteria Api 会导致问题

慕沐林林 2023-05-17 17:37:31
当我使用查询 API 更新一行,然后在同一事务中使用标准 API 检索数据时,我得到的是旧值,而不是更新后的值。为什么会这样,我该如何解决这个问题?我需要获取更新的值。@Service@Transactionalpublic class ExampleServiceImpl implements ExampleService {    @Autowired    ExampleRepository exampleRepository;    @Transactional    public void example() {        ExampleEntity entity = (ExampleEntity) sessionFactory.getCurrentSession().createCriteria(ExampleEntity.class).add(Restrictions.eq("id", 190001L)).uniqueResult();        exampleRepository.updateState(190001L, State.CLOSED);        ExampleEntity updatedEntity = (ExampleEntity)sessionFactory.getCurrentSession().createCriteria(ExampleEntity.class).add(Restrictions.eq("id", 190001L)).uniqueResult();        assertEquals(State.CLOSED, updatedEntity.getState());    }}@Repositorypublic class ExampleRepositoryImpl implements ExampleRepository {    public void updateState(Long id, State state) {        String updateScript = "update exampleEntity set state= '%s', " +                "VERSION = VERSION + 1 " +                "where ID = %s;";        updateScript = String.format(updateScript, state, id);        Query sqlQuery = sessionFactory.getCurrentSession().createSQLQuery(updateScript);        sqlQuery.executeUpdate();    }}注意:如果我删除第一行并且没有在开头检索实体,一切都会按我预期的那样进行。
查看完整描述

2 回答

?
ITMISS

TA贡献1871条经验 获得超8个赞

您正在混合本机 SQL 和休眠。基本上,当您第一次检索实体时,它会存储在您的会话 EntityManager 中。然后您使用纯 SQL 更新数据库中的行,但就休眠而言,实体并没有被弄脏,因为它不够聪明,无法理解纯 SQL 与对象模型的关系。当你第二次检索它时,它只是给你它已经缓存在 EntityManager 中的原始实体,而不是查询数据库。


解决方案是在更新后简单地从 EntityManager 中手动强制驱逐实体,如下所示: sessionFactory.getCurrentSession().evict(entity);


或者您可以简单地更新您获取的实体并将其持久化(最佳解决方案恕我直言,没有多余的 DAO 方法,以及远离数据库的最佳抽象):


ExampleEntity entity = (ExampleEntity) sessionFactory.getCurrentSession().createCriteria(ExampleEntity.class).add(Restrictions.eq("id", 190001L)).uniqueResult();


entity.setState(State.CLOSED);

entity.setVersion(e.getVersion() + 1);


sessionFactory.getCurrentSession().update(entity);

基本上...无论您选择哪个选项,都不要在同一事务中混合使用纯 SQL 和休眠查询。一旦 hibernate 加载了一个对象,它将从其缓存中返回相同的实体,直到它知道它是脏的。当使用纯 SQL 弄脏实体时,知道实体是脏的还不够聪明。如果您别无选择并且必须使用 SQL(在设计良好的休眠模型中永远不会出现这种情况),则调用 evict 来告诉休眠实体是脏的。


查看完整回答
反对 回复 2023-05-17
?
米脂

TA贡献1836条经验 获得超3个赞

当您获得结果时,您的交易仍未提交 - 这就是您获得“旧”价值的原因。



查看完整回答
反对 回复 2023-05-17
  • 2 回答
  • 0 关注
  • 116 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信