猿问

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

当我使用查询 API 更新一行,然后在同一事务中使用标准 API 检索数据时,我得到的是旧值,而不是更新后的值。为什么会这样,我该如何解决这个问题?我需要获取更新的值。


@Service

@Transactional

public 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());

    }


}


@Repository

public 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();

    }

}

注意:如果我删除第一行并且没有在开头检索实体,一切都会按我预期的那样进行。


慕沐林林
浏览 117回答 2
2回答

ITMISS

您正在混合本机 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 来告诉休眠实体是脏的。

米脂

当您获得结果时,您的交易仍未提交 - 这就是您获得“旧”价值的原因。
随时随地看视频慕课网APP

相关分类

Java
我要回答