Hibernate更新前后数据打印异常问题求助
问题描述
执行JPQL的Update语句成功更新数据库后,再次查询同一员工数据,打印结果仍为更新前的旧值,怀疑问题出在EntityManager上。
代码如下:
EntityManagerFactory factory = Persistence.createEntityManagerFactory("exercise"); EntityManager entityManager = factory.createEntityManager(); entityManager.getTransaction().begin(); Scanner scanner = new Scanner(System.in); String address = scanner.nextLine(); String lastName = scanner.nextLine(); Employee employee = findEmployee(entityManager, lastName); printEmployeeData(employee); // Prints Employee data before the Update entityManager.createQuery( "UPDATE Employee e" + " SET e.address = :address" + " WHERE e.lastName = :name") .setParameter("address", address) .setParameter("name", lastName) .executeUpdate(); // Successfully updated the Employee System.out.printf("%n%n"); employee = findEmployee(entityManager, lastName); printEmployeeData(employee); // Prints the same output as the one before the Update entityManager.getTransaction().commit(); entityManager.close(); private static Employee findEmployee(EntityManager entityManager, String lastName) { return entityManager.createQuery("SELECT e FROM Employee e" + " WHERE lastName = :lastName", Employee.class) .setParameter("lastName", lastName) .getSingleResult(); }
问题原因
你猜的没错,问题确实出在EntityManager的**一级缓存(持久化上下文)**上:
- 第一次查询后,Employee对象已经被存入EntityManager的一级缓存中;
- 执行JPQL的
executeUpdate()是直接操作数据库的批量更新,不会同步更新EntityManager缓存里的对象; - 第二次查询时,EntityManager会优先从缓存中取已存在的Employee对象,而不会去数据库拉取最新更新的数据。
解决办法
可以用以下几种方式解决:
方法1:清除EntityManager缓存
在执行executeUpdate()之后,调用entityManager.clear()清空持久化上下文,这样第二次查询就会从数据库获取最新数据:
entityManager.createQuery( "UPDATE Employee e" + " SET e.address = :address" + " WHERE e.lastName = :name") .setParameter("address", address) .setParameter("name", lastName) .executeUpdate(); // 清除缓存 entityManager.clear(); System.out.printf("%n%n"); employee = findEmployee(entityManager, lastName); printEmployeeData(employee); // 现在会打印更新后的数据
方法2:刷新指定对象
如果不想清空整个缓存,可以对原有的Employee对象调用refresh()方法,强制从数据库同步最新数据(注意这一步要在更新之后、重新查询之前做):
entityManager.createQuery(...) .executeUpdate(); // 刷新缓存中的employee对象 entityManager.refresh(employee); System.out.printf("%n%n"); printEmployeeData(employee); // 直接打印刷新后的对象,无需重新查询
方法3:查询时设置刷新模式
在查询语句中设置刷新模式为RefreshModeType.REFRESH,强制查询时从数据库获取最新数据,绕过缓存:
private static Employee findEmployee(EntityManager entityManager, String lastName) { return entityManager.createQuery("SELECT e FROM Employee e" + " WHERE lastName = :lastName", Employee.class) .setParameter("lastName", lastName) .setHint(QueryHints.REFRESH_MODE, RefreshModeType.REFRESH) .getSingleResult(); }
内容的提问来源于stack exchange,提问作者user17831294
相关产品推荐
相关产品推荐

