如何防止 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 缓存?的主要内容,如果未能解决你的问题,请参考以下文章

如何防止超卖

在winform当中提交数据,如何防止重复提交?

PostgreSQL如何防止表太大?

如何彻底防止SQL注入?

如何防止VBS的错误提示

https如何防止会话劫持