做的一個小項目裏面需要根據不同的角色顯示不同的菜單,於是將數據庫設計爲如下形式:
用戶表Admin(id, user_name, role_id)
角色表Role(id, name)
菜單表Menu(id, name, url)
角色菜單表RoleMenu(id, role_id, menu_id)
其中用戶表和角色表存在一對一關聯,角色表和菜單表存在着多對多關聯。系統採用了Hibernate框架,各實體定義如下:
public class Admin implements Serializable{ public Integer id; public Role role; … @OneToOne @JoinColumn(name=”role_id”) public Role getRole(){ return this.getRole(); } } public class Role implements Serializable{ public Integer id; public Set<Menu> menus; … @ManyToMany @JoinTable(name=”role_menu” joinColumns= {@JoinColumn(name="role_id")}, inverseJoinColumns={@JoinColumn(name="menu_id")}) public Set<Menu> getMenus(){ return menus; } }
用戶登錄採用ajax實現,登錄成功後跳轉到IndexAction動態地讀取菜單信息,代碼如下:
public Map<String, List<Menu>> findUserMenus(Admin admin) { // TODO Auto-generated method stub Set<Menu>menus = admin.getRole().getMenus(); Map<String,List<Menu>> map = new HashMap<String, List<Menu>>(); for(Menu menu : menus){ Stringid = menu.getId(); if(id.length() > 2){ StringparentId = id.substring(0, 2); MenuparentMenu = menuDao.queryById(parentId); Stringtext = parentMenu.getText(); List<Menu>lstMenu = (List<Menu>)map.get(text); if(lstMenu == null){ lstMenu= newArrayList<Menu>(); } lstMenu.add(menu); map.put(text,lstMenu); } } return map; }
但登錄成功後出現如下錯誤:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:cn.edu.qfnu.main.model.Role.menus, could not initialize proxy - no Session。
若將Role實體中menus的fetch類型改爲EAGER則沒有錯。在web.xml中已經配置了OpenSessionInViewFilter。折騰了很久才解決。原來OpenSessionInViewFilter用來把一個Hibernate Session和一次完整的請求過程對應的線程相綁定,也就是說,在一次請求過程中,Hibernate Session是不會關閉的,懶加載也因此能用。
我的問題是,在登錄請求後又發送了一次請求,此時通過session中保存的admin對象獲取menus對象的Session已經關閉,因此會出現上述錯誤。
記錄下來,避免以後再犯類似的錯誤。