1. 程式人生 > >Hibernate級聯儲存與刪除

Hibernate級聯儲存與刪除

   Hibernate為程式設計師提供一種級聯操作,在編寫程式時,通過Hibernate的級聯功能可以很方便的操作資料庫的主從表的資料,我們最常用的級聯是級聯儲存和級聯刪除,下面分別來看一下級聯儲存和級聯刪除。

       我準備了MenuPanelMenu兩個物件,先來看一下兩個物件的關係

       從上圖可以看出,MenuPanelMenu是一對多的關係,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;
	}

       在MenugetChildren()的方法中標上下面的註解

@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;
	}
	
	
}