如何防止 NamedStoredProcedureQueries 的休眠 4 缓存?
Posted
技术标签:
【中文标题】如何防止 NamedStoredProcedureQueries 的休眠 4 缓存?【英文标题】:How to prevent hibernate 4 caches for NamedStoredProcedureQueries? 【发布时间】:2014-08-17 17:35:06 【问题描述】:我正在实现一个基于 spring 3.2.8、jpa2.1 和 hibernate 4.3.5 的网络应用程序。我想知道如何防止休眠缓存特定的Named Stored Procedure Query
。
我尝试过 entityManager.clear(),但我认为它会清除所有缓存的实体值,因此它不是最佳解决方案!!
注意:我使用@NamedStoredProcedureQueries
来定义存储过程并通过以下方式调用它
entityManager.createNamedStoredProcedureQuery()
方法获取结果
添加:
表人:
personp# as PK, ...
表person_value:
person_valuepv# as PK, p# as foreign key from table person, ...
查看view1:
select *,check_value(dbo.person.p#) as has_value from person
函数check_value(输入):
如果 person_value 中有一条 p# 等于输入的记录,则返回 1。
存储过程SPS_VIEW1:
select * from view1
where p#=@p#
sql server视图的实体类view1:
@Entity
@Table(name = "view1")
@NamedStoredProcedureQueries(
@NamedStoredProcedureQuery(name = "getV1Records", procedureName = "SPS_VIEW1",
resultClasses = View1.class,
@parameters = @StoredProcedureParameter(name = "p#", type = String.class)))
public class View1
@Id
@Column(name = "p#")
private String personId;
@Column(name = "hasValue")
private boolean value;
<getters and setters>
服务类:
@Service("personService")
public class PersonService()
...
private EntityManager entityManager;
<getters and setters>
...
public List<View1> getAll(String pno)
SqlParameterValue p = new SqlParameterValue(new SqlParameter("p#", Types.VARCHAR), pno);
StoredProcedureQuery spq = entityManager.createNamedStoredProcedureQuery("getV1Records");
spq.setParameter(p.getName(), p.getValue());
return list;
控制器类:
@Controller("PersonController")
public class PersonController
...
@Autowired
private PersonService personService;
...
@RequestMapping("/person")
public personInfo(HttpServletRequest request)
String pno = request.getParameter("pno");
ModelAndView mv = new ModelAndView("person");
List<View1> list = personService.getAll(pno);
mv.addObject("view1_list", list);
return mv;
...
当我用 p# 打电话给getAll()
时,例如'p14521' 第一次在我的控制器中,表 person_value 中没有 p# 'p14521' 的记录,它会正常工作并且一切正常,但是当我用 p# 'p14521' 向 person_value 添加了一条记录,现在有一条 p# 'p14521' 的记录,然后再次调用 getAll()
输出列表。查询的输出列表似乎被缓存了。
【问题讨论】:
您是在 Spring 控制器还是在服务层中使用 @Transactional(readOnly = true) ?在上面的代码中,您是否检查了 spq 参数是否设置正确?如果可能,请提供更多详细信息,说明您如何从控制器调用以及如何在 getAll 中填充列表 不,我没有使用@Transactional(readOnly = true)。我已将控制器类代码添加到我的问题中。 【参考方案1】:您可以通过指定以下提示来告诉 hibernate 不要从缓存中获取数据:-
hints = @QueryHint(name = "org.hibernate.cacheable", value = "false") ,
试试这个:-
@NamedStoredProcedureQueries(
@NamedStoredProcedureQuery(
name="proc1",
resultClass=.....class,
hints = @QueryHint(name = "org.hibernate.cacheable", value = "false") ,
procedureName="Proc1",
parameters=...
),
@NamedStoredProcedureQuery(
name="proc2",
resultClass=.....class,
hints = @QueryHint(name = "org.hibernate.cacheable", value = "false") ,
procedureName="Proc2",
parameters=...
))
【讨论】:
谢谢,我之前试过了,但是没用。我在休眠时没有缓存配置。根据java.dzone.com/articles/pitfalls-hibernate-second-0,我想我应该先做缓存配置,然后这个查询提示才会起作用??? 无论您是否指定了 hibernate 查询缓存属性,此查询提示都将起作用,这意味着使用此查询提示,hibernate 必须始终对数据库执行查询。您如何确定它不起作用?【参考方案2】:Hibernate 默认不缓存查询结果。您必须启用二级缓存查询并指示缓存当前正在执行的查询。
Hibernate 的默认 1 级缓存是一个实体缓存,它会在您加载实体时启动:find/load 或 HQL/Criteria 查询。
我认为您的存储过程结果根本没有被缓存。
您的问题可能与您的存储过程未触发的Hibernate AUTO flush mode 有关。
在执行存储过程之前触发手动刷新:
em.flush();
另外,您没有在 getAll 方法中调用查询 getResultList:
所以应该是这样的:
em.flush();
return spq.getResultList();
【讨论】:
谢谢,但我确定数据已缓存,因为当我清除 entityManager 时,列表将被更新。 检查我更新的答案。它可能与自动刷新模式有关。在存储过程调用之前触发手动刷新。以上是关于如何防止 NamedStoredProcedureQueries 的休眠 4 缓存?的主要内容,如果未能解决你的问题,请参考以下文章