hibernate多对多关联关系

数据库的多对多

1,数据库中不能直接映射多对多

处理:创建一个桥接表(中间表),将一个多对多关系转换成两个一对多

  1. 数据库多表联接查询,永远就是二个表的联接查询

        A   B   C  D
           t1   C
                t2 D
                   t3
    
  2. 交叉连接
    笛卡尔查询(交叉查询)加上条件与内连接没有区别

select b.book_name,t.bid from t_book b,t_book_category t where b.book_id=t.bid
  1. 外连接:left(左)/right(右)/full(左右)
    左外连接 (left将左边的表看成主表)right将右边的表看成主表full(左右都看成主表)
    主从表:连接条件不成立时,主表记录永远保留,与null匹配

多对多注意事项

1 一定要定义一个主控方
2 多对多删除
2.1 主控方直接删除
2.2 被控方先通过主控方解除多对多关系,再删除被控方
2.3 禁用级联删除
3 关联关系编辑,不需要直接操作桥接表,hibernate的主控方会自动维护

  <set table="t_book_category" name="categories" cascade="save-update" inverse="false" >
  		
  	<!-- 在哪个实体映射文件里面,key就是一对多方的一 -->
  	<!-- one -->
  	<key column="bid"></key>
  	
  	<!-- 多方 -->
  	<many-to-many column="cid" class="com.zking.entity.Category"></many-to-many>
  </set>

项目中的类的介绍

在这里插入图片描述

数据库表与实体类

-- 书本类别表
create table t_category
(
   category_id int primary key auto_increment,
   category_name varchar(50) not null
);

-- 书本表
create table t_book
(
   book_id int primary key auto_increment,
   book_name varchar(50) not null,
   price float not null
);


-- 桥接表
-- 定义三个列,其实只要两个列
-- 一个类别对应多本书,一本书对应多个类别
create table t_book_category
(
  bcid int primary key auto_increment,  
  bid int not null,
  cid int not null,
  foreign key(bid) references t_book(book_id),
  foreign key(cid) references t_category(category_id)
);

select * from t_category;
select * from t_book;
select * from t_book_category;


insert into t_book(book_id, book_name, price) values(1,'西游记',50);
insert into t_book(book_id, book_name, price) values(2,'红楼梦',50);
insert into t_book(book_id, book_name, price) values(3,'水浒',50);
insert into t_book(book_id, book_name, price) values(4,'三国演义',50);
insert into t_book(book_id, book_name, price) values(5,'javaoop',100);


insert into t_category(category_id, category_name) values(1,'古典');
insert into t_category(category_id, category_name) values(2,'神话');
insert into t_category(category_id, category_name) values(3,'历史');



insert into t_book_category(bid, cid) values(1,1);
insert into t_book_category(bid, cid) values(1,2);
insert into t_book_category(bid, cid) values(2,1);
insert into t_book_category(bid, cid) values(3,1);
insert into t_book_category(bid, cid) values(3,3);
insert into t_book_category(bid, cid) values(4,1);
insert into t_book_category(bid, cid) values(4,3);
数据库表字段——》属性
Book实体
package com.liuchunming.entity ;

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

public class Book {
	private Integer bookId;
	private String bookName;
	private Float price;
	
	//多对多关联关系,可以看做两个一对多
	Set<Category> category=new HashSet<Category>();

	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> getCategory() {
		return category;
	}

	public void setCategory(Set<Category> category) {
		this.category = category;
	}

	/**
	 * @param bookId
	 * @param bookName
	 * @param price
	 * @param category
	 */
	public Book(Integer bookId, String bookName, Float price, Set<Category> category) {
		super();
		this.bookId = bookId;
		this.bookName = bookName;
		this.price = price;
		this.category = category;
	}

	/**
	 * 
	 */
	public Book() {
		super();
	}

	@Override
	public String toString() {
		return "Book [bookId=" + bookId + ", bookName=" + bookName + ", price=" + price + ", category=" + category
				+ "]";
	}
	
}
Category实体
package com.liuchunming.entity;

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

public class Category {
	private Integer categoryId;
	private String categoryName;
	
	private Set<Book> books=new HashSet<Book>();

	/**
	 * 
	 */
	public Category() {
		super();
	}

	public Integer getCategoryId() {
		return categoryId;
	}

	public void setCategoryId(Integer categoryId) {
		this.categoryId = categoryId;
	}

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

	/**
	 * @param categoryId
	 * @param categoryName
	 * @param books
	 */
	public Category(Integer categoryId, String categoryName, Set<Book> books) {
		super();
		this.categoryId = categoryId;
		this.categoryName = categoryName;
		this.books = books;
	}

	@Override
	public String toString() {
		return "Category [categoryId=" + categoryId + ", categoryName=" + categoryName + ", books=" + books + "]";
	}
	
}
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 name="com.liuchunming.entity.Book" table="t_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>
		<!-- 建立映射关联关系 -->
		<!--  
			name:实体类里的集合属性
			cascade:标明级联操作	——save-update:级联更新
			inverse:是否执行级联操作
			column:用什么关联丛表
		 -->
		 <!-- 
		 name:属性名
		 key:外键
		 cascade:级联保存或更新
		 inverse:把对方设置为主控方 -->
		<set table="t_book_category"
		name="category" 
		cascade="save-update" 
		inverse="false">
		<!-- 在哪个实体映射文件里面,key就一方(one) -->
		<!-- one -->
		<key column="bid"></key>
		<!-- 多方 -->
		<many-to-many column="cid" class="com.liuchunming.entity.Category"/>
		</set>
	</class>
</hibernate-mapping>
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 name="com.liuchunming.entity.Category" table="t_category">
		<id name="categoryId" type="java.lang.Integer" column="category_id">
			<generator class="increment"></generator>
		</id>
		<property name="categoryName" type="java.lang.String" column="category_name"></property>
		<!-- 建立映射关联关系 -->
		<!--  
			name:实体类里的集合属性
			cascade:标明级联操作	——save-update:级联更新
			inverse:是否执行级联操作
			column:用什么关联丛表
		 -->
		 <!-- 
		 name:属性名
		 key:外键
		 cascade:级联保存或更新
		 inverse:把对方设置为主控方 -->
		<set table="t_book_category"
		name="books" 
		cascade="save-update" 
		inverse="true">
		<!-- 在哪个实体映射文件里面,key就一方(one) -->
		<!-- one -->
		<key column="cid"></key>
		<!-- 多方 -->
		<many-to-many column="bid" class="com.liuchunming.entity.Book"/>
		</set>
	</class>
</hibernate-mapping>
SessionFactoryUtils工具类
package com.liuchunming.util;

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

public class SessionFactoryUtils {

	private static final String 
			HIBERNATE_CONFIG_FILE="hibernate.cfg.xml";
	
	private static ThreadLocal<Session> threadLocal=
			new ThreadLocal<Session>();
	
	//创建数据库的会话工厂
	private static SessionFactory sessionFactory;
	
	//读取hibernate核心配置
	private static Configuration configuration;
	
	static {
		try {
			configuration=new Configuration();
			configuration.configure(HIBERNATE_CONFIG_FILE);
			//创建Session会话工厂
			sessionFactory=configuration.buildSessionFactory();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static Session openSession() {
		Session session = threadLocal.get();
		if(null==session) {
			session=sessionFactory.openSession();
			threadLocal.set(session);
		}
		return session;
	}
	
	public static void closeSession() {
		Session session = threadLocal.get();
		if(null!=session) {
			if(session.isOpen())
				session.close();
			threadLocal.set(null);
		}
	}
	
	public static void main(String[] args) {
		Session session = SessionFactoryUtils.openSession();
		System.out.println("Session状态:"+session.isOpen());
		System.out.println("Session会话已打开");
		SessionFactoryUtils.closeSession();
		System.out.println("Session会话已关闭");
	}
}
BookDao方法
package com.liuchunming.dao;

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

import com.liuchunming.entity.Book;
import com.liuchunming.util.SessionFactoryUtils;

public class BookDao {
	//新增
	public void save(Book book) {
		Session session = SessionFactoryUtils.openSession();
		Transaction tr = session.beginTransaction();
		
		//CRUD
		session.save(book);
		tr.commit();
		SessionFactoryUtils.closeSession();
	}
	
	public void del(Book book) {
		Session session = SessionFactoryUtils.openSession();
		Transaction tr = session.beginTransaction();
		//CRUD (主控方删除)先查后删
		Book b = session.get(Book.class, book.getBookId());
		if(null!=b) {
			session.delete(b);
		}
		tr.commit();
		SessionFactoryUtils.closeSession();
	}
}
CategroyDao方法
package com.liuchunming.dao;

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

import com.liuchunming.entity.Book;
import com.liuchunming.entity.Category;
import com.liuchunming.util.SessionFactoryUtils;

public class CategoryDao {
	public void del(Category category) {
		Session session = SessionFactoryUtils.openSession();
		Transaction tr = session.beginTransaction();
		//CRUD
		Category c = session.get(Category.class, category.getCategoryId());
		if(null!=c) {
			//解除关联关系
			/*for (iterable_type iterable_element : iterable) {
				
			}*/
			
			for(Book b:c.getBooks()) {
				b.getCategory().remove(c);
			}
			session.delete(c);
		}
		
		tr.commit();
		SessionFactoryUtils.closeSession(); 
	}
}

Junit测试
package com.liuchunming.dao;

import com.liuchunming.entity.Book;
import com.liuchunming.entity.Category;

import junit.framework.TestCase;

public class BookDaoTest extends TestCase {
	Book book =null;
	BookDao bookDao=new BookDao();
	CategoryDao categoryDao=new CategoryDao();
	Category category =null;
	
	protected void setUp() throws Exception {
		book=new Book();
		category =new Category();
	}
	public void testSave() {
		book.setBookName("java面试题");
		book.setPrice(99f);
		
		category.setCategoryId(3);//设置从"历史"
		category.setCategoryName("历史");
		book.getCategory().add(category);
		
		bookDao.save(book);
	}
	//主控方:直接删除
//	public void testdel() {
//		book.setBookId(6);
//		bookDao.del(book);
//	}
	//被控方:需要先解除关联关系(主控方会维护桥接表,删除时发现有引用会先删除桥接表再删自己)
		public void testdel2() {
			book.setBookId(6);
			bookDao.del(book);
		}

}
先测试增加

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试删除

在这里插入图片描述
在这里插入图片描述

总结

今天的分享就到这里了如果有什么不对的地方欢迎大家在评论区留言交流改进!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值