经常有树形结构的数据保存在一张二维表中,例如组织架构,多级菜单等。一般是在一张表中使用ID,PID作关联。我项目中的是这样一个树形菜单:
@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "Menu")
@Table(name = "DDT_MENU", schema = "CBA", uniqueConstraints = @UniqueConstraint(columnNames = "ENNAME"))
public class Menu implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private EMenu enname;
private String zhname;
private Long pid;
private String grade;
private Menu parent;
private Set<Menu> children=new TreeSet<Menu>();
public Menu() {
}
下面是关联配置:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PID", nullable = true)
public Menu getParent() {
return parent;
}
@OneToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY, mappedBy = "pid")
public Set<Menu> getChildren() {
return children;
}
这些数据由于很修改少,访问频繁,因此很适合放在缓存中。
下面是EhCache配置:
<cache name="Menu"
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
我在程序中用递归方式获得整个树形结构的数据,观察后台Hibernate输出的语句,一直都没使用上缓存。根据Hibernate使用缓存的机制:
1) Hibernate首先根据这些查询信息组成一个Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。 2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。 3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。
来看,也确实使用不上,因为每次递归getChildren()的查询条件不同。现在不知道咋搞,请各位大侠不吝赐教。
经过我仔细的调试,发现使用配置对象之间的关联关系(@OneToMany )得到的关联对象并不会放到二级缓存中。例如上述例子中,我遍历整棵树,在递归得到孩子菜单时是通过Menu类的getChildren()方法,调用此方法得到的孩子菜单对象hibernate并不会放到二级缓存中。因此,为了使用上缓存,我自己写了另外一个方法findMyChildren(),代码如下:
@SuppressWarnings("unchecked")
public HashSet<Menu> findMyChildren(Menu m) {
DetachedCriteria dc = DetachedCriteria.forClass(Menu.class);
dc.add(Restrictions.eq("pid", m.getId()));
List<Menu> menus = hibernateTemplateUseCache.findByCriteria(dc);
HashSet<Menu> menusSet = new HashSet<Menu>(menus);
return menusSet;
}
然后递归取得孩子菜单时使用此方法,此方法返回的孩子菜单都会被保存到二级缓存中,以后访问时会直接从缓存中拿。由于项目的菜单在程序运行过程中不会被修改,因此只需从数据库加载一次。于是修改EhCache配置:
<cache name="Menu"
maxElementsInMemory="200"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
这样一来,就达到了树形结构数据永远去缓存中取的目的。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。