Hibernate級聯儲存與刪除
Hibernate為程式設計師提供一種級聯操作,在編寫程式時,通過Hibernate的級聯功能可以很方便的操作資料庫的主從表的資料,我們最常用的級聯是級聯儲存和級聯刪除,下面分別來看一下級聯儲存和級聯刪除。
我準備了MenuPanel和Menu兩個物件,先來看一下兩個物件的關係
從上圖可以看出,MenuPanel和Menu是一對多的關係,Menu表同時存在多個子節點,用parentId代表該節點的父節點。
在JPA中,配置級聯操作我們可以用cascade=CascadeType.ALL,意思是支援所有的級聯操作,網上有很多文章說級聯儲存用CascadeType.PERSIST,這也是可以的,我們分別在程式碼中使用以上兩個型別。在MenuPane的getChildren()方法中標上下面的註解:
@OneToMany(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY,mappedBy="menu")
public List<Menu> getChildren() {
return children;
}
在Menu的getChildren()的方法中標上下面的註解
@OneToMany(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY,mappedBy="menu") public List<Menu> getChildren() { return children; }
以上程式碼實現級聯儲存的配置,我們需要在業務邏輯中為物件設定關係,這樣Hibernate才能自動實現級聯儲存,如果只是配置了級聯操作,而沒有在物件中設定物件之前的關係,Hibernate是無法實現級聯儲存的功能的。
首先例項化MenuPanel
MenuPanel panel1 = new MenuPanel("基礎設定");
再例項化幾個Menu
Menu menuCard=new Menu("會員卡設定",""); menuCard.setLeaf(false); Menu menu1 = new Menu("卡型別設定", "basicOperation/queryCardType"); Menu menu2 = new Menu("站點設定", "basicOperation/querySite"); Menu menu3 = new Menu("操作員授權", "basicOperation/queryOperatorSet"); Menu menu4 = new Menu("密碼修改", "test.do"); Menu menu5 = new Menu("消費專案管理", "test1.do");
我們要把menuCard作為menu1的父節點,故作如下設定
List<Menu> cardChildMenus=new ArrayList<Menu>();
cardChildMenus.add(menu1);
menuCard.setChildren(cardChildMenus);//把卡型別設定作為會員卡設定的子選單
設定物件之間的關係,這一步很關鍵,直接影響儲存結果
menu1.setMenu(menuCard);//為會員卡設定設定卡型別設定,以支援級聯儲存
menuCard.setMenuPanel(panel1);
//設定Menu屬於MenuPanel
menu2.setMenuPanel(panel1);
menu3.setMenuPanel(panel1);
menu4.setMenuPanel(panel1);
menu5.setMenuPanel(panel1);
//將Menu新增到MenuPanel
panel1.getMenus().add(menuCard);
panel1.getMenus().add(menu2);
panel1.getMenus().add(menu3);
panel1.getMenus().add(menu4);
panel1.getMenus().add(menu5);
具體程式碼:
@Override
public boolean testAdd() {
List<MenuPanel> menuPanels=new ArrayList<MenuPanel>();
MenuPanel panel1 = new MenuPanel("基礎設定");
Menu menuCard=new Menu("會員卡設定","");
menuCard.setLeaf(false);
Menu menu1 = new Menu("卡型別設定", "basicOperation/queryCardType");
Menu menu2 = new Menu("站點設定", "basicOperation/querySite");
Menu menu3 = new Menu("操作員授權", "basicOperation/queryOperatorSet");
Menu menu4 = new Menu("密碼修改", "test.do");
Menu menu5 = new Menu("消費專案管理", "test1.do");
menu1.setMenu(menuCard);//為會員卡設定設定卡型別設定,以支援級聯儲存
menuCard.setMenuPanel(panel1);
menu2.setMenuPanel(panel1);
menu3.setMenuPanel(panel1);
menu4.setMenuPanel(panel1);
menu5.setMenuPanel(panel1);
List<Menu> cardChildMenus=new ArrayList<Menu>();
cardChildMenus.add(menu1);
menuCard.setChildren(cardChildMenus);//把卡型別設定作為會員卡設定的子選單
panel1.getMenus().add(menuCard);
panel1.getMenus().add(menu2);
panel1.getMenus().add(menu3);
panel1.getMenus().add(menu4);
panel1.getMenus().add(menu5);
MenuPanel panel2 = new MenuPanel("日常操作");
Menu menu10 = new Menu("發行新卡", "operate/cardList?type=add");
Menu menu11 = new Menu("存款入卡", "operate/cardList?type=depositMoney");
Menu menu12 = new Menu("卡中取款", "operate/cardList?type=drawMoney");
Menu menu13 = new Menu("獎品管理", "operate/cardList?type=prize");
Menu menu14 = new Menu("卡掛失", "operate/cardList?type=reportLoss");
Menu menu15 = new Menu("卡解掛", "operate/cardList?type=cancelLoss");
Menu menu16 = new Menu("並卡", "operate/cardList?type=mergeCard");
Menu menu17 = new Menu("補辦新卡", "operate/cardList?type=mendCard");
Menu menu18 = new Menu("回收舊卡", "operate/cardList?type=recycleCard");
Menu menu19 = new Menu("維護", "operate/cardList?type=maintain");
menu10.setMenuPanel(panel2);
menu11.setMenuPanel(panel2);
menu12.setMenuPanel(panel2);
menu13.setMenuPanel(panel2);
menu14.setMenuPanel(panel2);
menu15.setMenuPanel(panel2);
menu16.setMenuPanel(panel2);
menu17.setMenuPanel(panel2);
menu18.setMenuPanel(panel2);
menu19.setMenuPanel(panel2);
panel2.getMenus().add(menu10);
panel2.getMenus().add(menu11);
panel2.getMenus().add(menu12);
panel2.getMenus().add(menu13);
panel2.getMenus().add(menu14);
panel2.getMenus().add(menu15);
panel2.getMenus().add(menu16);
panel2.getMenus().add(menu17);
panel2.getMenus().add(menu18);
panel2.getMenus().add(menu19);
menuPanels=new ArrayList<MenuPanel>();
menuPanels.add(panel1);
menuPanels.add(panel2);
return menuPanelDao.add(menuPanels);
}
執行一下單元測試,看一下效果
@Test
public void test()
{
// menuPanelService.delete();
menuPanelService.testAdd();
}
Hibernate: insert into MENUPANEL (text, id) values (?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENUPANEL (text, id) values (?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
大家可以看到資料全部儲存到資料庫中了,有圖有真像。
圖一:MenuPanel表
圖二:Menu表
再來看一下級聯刪除,級聯刪除可以用CascadeType.REMOVE,先在Menu中的getMenuPanel()方法中加上如下配置,由於我們已經在MenuPanel中配置了cascade=CascadeType.ALL,所以,下面的配置是可以忽略的,之所以這麼做,是為了當從Menu中刪除物件時能級聯刪除MenuPanel。
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE}, targetEntity=MenuPanel.class)
在getMenu()方法中也加上如下配置
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE}, targetEntity=Menu.class)
同在要把物件之間的關係解除
menus.get(j).setMenuPanel(null);
具體的程式碼
@Override
public boolean delete() {
// TODO Auto-generated method stub
Session session = null;
try {
session =getSession();
Query query = session.createQuery("from MenuPanel");
List<MenuPanel> list = query.list();
for (int i = 0; i < list.size(); i++) {
MenuPanel mp = list.get(i);
List<Menu> menus = mp.getMenus();
for (int j = 0; j < menus.size(); j++) {
menus.get(j).setMenuPanel(null);
clareChild(menus.get(j).getChildren());
}
super.delete(mp);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
// session.close();
}
}
執行結果
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENUPANEL where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENU where id=?
Hibernate: delete from MENUPANEL where id=?
POJO類的詳細程式碼如下:
package com.mcs.user.pojo;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import com.mcs.pojo.base.GenericObject;
/**
* 這個是MenuPanel對應的是accordion選單
* @author lishengbo
*
*/
@Entity
@Table(name = "MENUPANEL")
public class MenuPanel extends GenericObject {
private String text;
private List<Menu> menus=new ArrayList<Menu>();
public MenuPanel() {
}
public MenuPanel(String text) {
this.text = text;
}
public MenuPanel(long id,String text) {
this.text = text;
super.setId(id+"");
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
/**
* 一對多關聯Menu選單,作為Tree中的根節點,這裡使用立即載入和MenuPanel一起載入到客戶端,注意,一定要使用立即載入
* @return
*/
@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER,mappedBy="menuPanel")
public List<Menu> getMenus() {
return menus;
}
public void setMenus(List<Menu> menus) {
this.menus = menus;
}
}
package com.mcs.user.pojo;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import com.mcs.pojo.base.GenericObject;
@Entity
@Table(name="MENU")
public class Menu extends GenericObject{
private String text;
private String url;
private boolean leaf=true;//預設是葉子節點
private MenuPanel menuPanel;
private List<Menu> children;
private Menu menu;
public Menu() {
}
public Menu(String text, String url) {
super();
this.text = text;
this.url = url;
}
public Menu(long id,String text, String url,MenuPanel menuPanel) {
super();
super.setId(id+"");
this.text = text;
this.url = url;
this.menuPanel=menuPanel;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE}, targetEntity=MenuPanel.class)
@JoinColumn(name="menuPanelId",referencedColumnName="id",insertable=true,updatable=true)
public MenuPanel getMenuPanel() {
return menuPanel;
}
public void setMenuPanel(MenuPanel menuPanel) {
this.menuPanel = menuPanel;
}
@Column(length=1000)
public boolean isLeaf() {
return leaf;
}
public void setLeaf(boolean leaf) {
this.leaf = leaf;
}
@OneToMany(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY,mappedBy="menu")
public List<Menu> getChildren() {
return children;
}
public void setChildren(List<Menu> children) {
this.children = children;
}
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE}, targetEntity=Menu.class)
@JoinColumn(name="parentId",referencedColumnName="id",insertable=true,updatable=true)
public Menu getMenu() {
return menu;
}
public void setMenu(Menu menu) {
this.menu = menu;
}
}