1. 程式人生 > >Hibernate多對多的雙向關聯

Hibernate多對多的雙向關聯

Hibernate多對多關係:可以看作是兩個一對多,比如書籍與類別,書籍可以有多個類別,類別下可以有多本書籍

既然多對多可以看作兩個一對多,那麼維護只能交給一方進行維護,比如我做級聯新增時,如果雙方都維護,就會造成資料重複

準備:

SessionFactoryUtils類:用來管理session

package com.zking.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * 1.方便獲取session會話,用來操作資料庫
 * 2.用來檢驗所有對映的配置檔案是否準確
 * @author Li Jin Guo
 */
public class SessionFactoryUtils {
	private static SessionFactory sessionFactory;
	
	static {
		Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
		sessionFactory = cfg.buildSessionFactory();
	}
	
	public static Session getSession() {
		Session session = sessionFactory.getCurrentSession();
		if (session == null) {
			session = sessionFactory.openSession();
		}
		return session;
	}
	
	public static void closeSession() {
		Session session = sessionFactory.getCurrentSession();
		if (session != null && session.isOpen()) {
			session.close();
		}
	}
	
	public static void main(String[] args) {
		Session session = SessionFactoryUtils.getSession();
		session.beginTransaction();
		System.out.println(session.isConnected());
		SessionFactoryUtils.closeSession();
		System.out.println(session.isConnected());
	}
}

Book類:

package com.study.entity;

import java.util.HashSet;
import java.util.Set;

public class Book {
	private Integer bookId;
	private String bookName;
	private Float price;
	private Set<Category> categorys = new HashSet<Category>();
	private Integer initCategorys;//懶載入控制
	public Integer getBookId() {
		return bookId;
	}
	public void setBookId(Integer bookId) {
		this.bookId = bookId;
	}
	public String getBookName() {
		return bookName;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public Float getPrice() {
		return price;
	}
	public void setPrice(Float price) {
		this.price = price;
	}
	public Set<Category> getCategorys() {
		return categorys;
	}
	public void setCategorys(Set<Category> categorys) {
		this.categorys = categorys;
	}
	public Integer getInitCategorys() {
		return initCategorys;
	}
	public void setInitCategorys(Integer initCategorys) {
		this.initCategorys = initCategorys;
	}
}

Book類的對映檔案:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class table="t_hibernate_book" name="com.study.entity.Book">
		<id name="bookId" type="java.lang.Integer" column="book_id">
			<generator class="increment"></generator>
		</id>
		<property name="bookName" type="java.lang.String" column="book_name"></property>
		<property name="price" type="java.lang.Float" column="price"></property>
		
		<set table="t_hibernate_book_category" name="categorys" cascade="save-update" inverse="false">
			<key column="bid"></key>
			<many-to-many column="cid" class="com.study.entity.Category"/>
		</set>
	</class>
</hibernate-mapping>

Category類:

package com.study.entity;

import java.util.HashSet;
import java.util.Set;

public class Category {
	private Integer category_Id;
	private String categoryName;
	private Set<Book> books = new HashSet<Book>();
	private Integer initBook;
	public Integer getCategory_Id() {
		return category_Id;
	}
	public void setCategory_Id(Integer category_Id) {
		this.category_Id = category_Id;
	}
	public String getCategoryName() {
		return categoryName;
	}
	public void setCategoryName(String categoryName) {
		this.categoryName = categoryName;
	}
	public Set<Book> getBooks() {
		return books;
	}
	public void setBooks(Set<Book> books) {
		this.books = books;
	}
	public Integer getInitBook() {
		return initBook;
	}
	public void setInitBook(Integer initBook) {
		this.initBook = initBook;
	}
}

Category類對映檔案:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class table="t_hibernate_category" name="com.study.entity.Category">
		<id name="category_Id" type="java.lang.Integer" column="category_id">
			<generator class="increment"></generator>
		</id>
		<property name="categoryName" type="java.lang.String" column="category_name"></property>
		
		<set table="t_hibernate_book_category" name="books" cascade="save-update" inverse="true">
			<key column="cid"></key>
			<many-to-many column="bid" class="com.study.entity.Book"/>
		</set>
	</class>
</hibernate-mapping>

Book DAO層:

package com.study.dao;

import java.io.Serializable;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.study.entity.Book;
import com.study.entity.TreeNode;
import com.zking.util.SessionFactoryUtils;

public class BookDao {
	public Book get(Book book) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		Book b = session.get(Book.class, book.getBookId());
		if (b != null && new Integer(1).equals(book.getInitCategorys())) {
			Hibernate.initialize(b.getCategorys());
		}
		transaction.commit();
		session.close();
		return b;
	}
	
	public Integer add(Book book) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		Integer n = (Integer) session.save(book);
		transaction.commit();
		session.close();
		return n;
	}
	
	public void del(Book book) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		session.delete(book);
		transaction.commit();
		session.close();
	}
}

Category DAO層:

package com.study.dao;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.study.entity.Book;
import com.study.entity.Category;
import com.zking.util.SessionFactoryUtils;

public class CategoryDao {
	public Category get(Category category) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		Category c = session.get(Category.class, category.getCategory_Id());
		if (c != null && new Integer(1).equals(category.getInitBook())) {
			Hibernate.initialize(c.getBooks());
		}
		transaction.commit();
		session.close();
		return c;
	}
	
	public Integer add(Category category) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		Integer n = (Integer) session.save(category);
		transaction.commit();
		session.close();
		return n;
	}
	
	public void del(Category category) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		Category c = session.get(Category.class, category.getCategory_Id());
		for (Book b : c.getBooks()) {
			//c.getBooks().remove(b);
			b.getCategorys().remove(c);
		}
		session.delete(c);
		transaction.commit();
		session.close();
	}
}

級聯查詢:

1.根據書籍查詢類別

@Test
	public void testGet1() {
		Book book = new Book();
		book.setBookId(5);
		book.setInitCategorys(1);
		Book b = bookDao.get(book);
		System.out.println(b.getBookName());
		for (Category c : b.getCategorys()) {
			System.out.println(c.getCategoryName());
		}
	}

2.根據類別查詢書籍

@Test
	public void testGet2() {
		Category category = new Category();
		category.setCategory_Id(2);
		category.setInitBook(1);
		Category c = categoryDao.get(category);
		System.out.println(c.getCategoryName());
		for (Book b : c.getBooks()) {
			System.out.println(b.getBookName());
		}
	}

級聯新增:

注:主控方為Book類,所以只用Book能維護關係,因此增加時值有增加書籍時才能級聯增加,反過來級聯增加類別時,就只能增加類別

而且級聯增加時增加是持久化資料不是臨時資料

@Test
	public void testAdd1() {
		Book book = new Book();
		book.setBookName("不死不滅");
		book.setPrice(45f);
		
		Category category = new Category();
		category.setCategory_Id(8);
		book.getCategorys().add(this.categoryDao.get(category));
		bookDao.add(book);
	}

刪除:

注:這裡不是級聯刪除,級聯刪除是不推薦使用的,會因為雙向關聯關係刪除所有資料!!!

1.刪除Book的同時刪除對應關聯(主控方刪除)

public void testDel1() {
		Book book = new Book();
		book.setBookId(6);
		this.bookDao.del(book);
	}

2.刪除Category的同時刪除對應關聯(被控方刪除)

因為維護關係,如果直接刪除Category,會因為不刪除關聯資料而報外來鍵錯誤

解決:由主控方解除關聯關係,然後被控方再進行刪除

public void del(Category category) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		Category c = session.get(Category.class, category.getCategory_Id());//查詢category物件
		for (Book b : c.getBooks()) {//獲取該類別對應的所有book
			//c.getBooks().remove(b);
			b.getCategorys().remove(c);//book解除關係
		}
		session.delete(c);
		transaction.commit();
		session.close();
	}

刪除:

public void testDel2() {
		Category category = new Category();
		category.setCategory_Id(8);
		this.categoryDao.del(category);
	}