hibernate多对多关系维护

hibernate多对多关系维护主要是级联新增与级联删除,这里以书籍(Book)和书籍类别(Category)为例来讲解Hibernate关联映射中的多对多关联关系的维护,相关数据库设计、实体类、配置文件见:https://blog.csdn.net/weixin_42687829/article/details/83385610

两个配置文件的inverse属性共有四种组合方式:1、Book.hbm.xml:true,Category.hbm.xml:false代表的意思是将关系维护的责任交给Category;2、Book.hbm.xml:false,Category.hbm.xml:true代表的意思是将关系维护的责任交给Book;3、两个都为true;4、两个都为false。这里先以第二种配置方式为例:

1、级联新增

测试新增书本:

    /**
 * 新增书本的方法
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:05:40
 * @param book
 * @return
 */
public Integer save(Book book) {
	Session session = SessionFactoryUtil.getSession();
	Transaction transaction = session.beginTransaction();
	Integer bid = (Integer) session.save(book);
	transaction.commit();
	SessionFactoryUtil.closeSession();
	return bid;
}

    /**
 * 新增书本:填写书本信息->勾选复选框类别->提交
 * jdbc的做法:bookDao.add()、categoryDao.add()
 * hibernate做法:bookDao.add()
 * 
 * 配置:
 *	   book.hbm:false
 *	   category.hbm:true
 * 代表的意思是将关系维护的责任交给book
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:32:28
 */
@Test
public void testSaveBook() {
	Book book=new Book();
	book.setBookName("你是最好的自己");
	Category category=new Category();
	category.setCategoryId(3);
	/*
	 * 错误写法:book.getCategorys().add(category);
	 * 异常Caused by: 
	 * 	com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: 
	 * 		Column 'category_name' cannot be null
	 * 因为hibernate通过管理持久态对象来操作数据库,所以要先查询一下将category变成持久态
	 */
	book.getCategorys().add(this.categoryDao.get(category));
	this.save(book);
}

结果:书籍表和桥接表都新增成功,没有异常

测试新增书籍类别:

    /**
 * 新增类别的方法
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:14:04
 * @param category
 * @return
 */
public Integer save(Category category) {
	Session session = SessionFactoryUtil.getSession();
	Transaction transaction = session.beginTransaction();
	Integer cid = (Integer) session.save(category);
	transaction.commit();
	SessionFactoryUtil.closeSession();
	return cid;
}

    /**
 * 当配置为:
 *	   book.hbm:false
 *	   category.hbm:true时,操作category是不能往桥接表里添加数据的
 * 因为其代表的意思是将关系维护的责任交给book,所以这种添加方式是不可行的
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:42:37
 */
@Test
public void testSaveCategory() {
	Category category=new Category();
	category.setCategoryName("玄幻");
	Book book=new Book();
	book.setBookId(5);
	category.getBooks().add(this.bookDao.get(book));
	this.categoryDao.save(category);
}

结果:书籍列表新增成功,但桥接表没有新增,没有报异常

当配置都为true时测试新增书籍:

    /**
 * 当配置为:
 *	   book.hbm:true
 *	   category.hbm:true时会出现中间表无对象维护的情况,即书本能添加进去,但中间表无法添加
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:46:22
 */
@Test
public void testSaveBook2() {
	Book book=new Book();
	book.setBookName("你是最好的自己2");
	Category category=new Category();
	category.setCategoryId(3);
	book.getCategorys().add(this.categoryDao.get(category));
	this.save(book);
}

结果:书本能添加进去,但中间表无法添加

当配置都为false时测试新增书籍:

     /**
 * 当配置为:
 *	   book.hbm:false
 *	   category.hbm:false
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:46:22
 */
@Test
public void testSaveBook3() {
	Book book=new Book();
	book.setBookName("你是最好的自己2");
	Category category=new Category();
	category.setCategoryId(3);
	book.getCategorys().add(this.categoryDao.get(category));
	this.save(book);
}

结果:书本能添加进去,中间表也能添加进去,但若再新增书本类别且是同一组关系,依然能新增进去,造成数据重复的现象

2、级联删除(以第二种配置方式为例)

删除主控方(Book):

    /**
 * 删除书本的方法
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:50:19
 * @param book
 */
public void del(Book book) {
	Session session = SessionFactoryUtil.getSession();
	Transaction transaction = session.beginTransaction();
	session.delete(book);
	transaction.commit();
	SessionFactoryUtil.closeSession();
}

    /**
 * 删除主控方book
 * 结论:一并将从表关联的中间表信息删除
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:52:13
 */
@Test
public void testDelBook() {
	Book book=new Book();
	book.setBookId(5);//删除书本ID为5的
	this.del(book);
}

结果:一并将从表关联的中间表信息删除

删除被控方(Category):

    /**
 * 删除类别(被控方)
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:51:05
 * @param category
 */
public void del(Category category) {
	Session session = SessionFactoryUtil.getSession();
	Transaction transaction = session.beginTransaction();
	session.delete(category);
	transaction.commit();
	SessionFactoryUtil.closeSession();
}

    /**
 * 删除被控方category
 * 结论:删除失败
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:54:52
 */
@Test
public void testDelCategory() {
	Category category=new Category();
	category.setCategoryId(2);
	this.del(category);
}

以上做法会删除失败且报异常:Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (test.t_hibernate_book_category, CONSTRAINT t_hibernate_book_category_ibfk_2 FOREIGN KEY (cid) REFERENCES t_hibernate_category (category_id)),这是因为主外键约束出现的异常。

解决:被控方先通过主控方解除多对多关系,再删除被控方。

    /**
 * 删除类别(被控方)
 * 若直接删除会失败,因为被控方被中间表所引用
 * 解决:1、解除关联关系(先删除中间表的引用数据)
 * 		2、再去删除主表信息
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:51:05
 * @param category
 */
public void del(Category category) {
	Session session = SessionFactoryUtil.getSession();
	Transaction transaction = session.beginTransaction();
	Category c = session.get(Category.class, category.getCategoryId());
	//c里面保存着与某一些书籍相关联的关系
	for (Book b : c.getBooks()) {
		/*
		 * 注意关联关系是交于book,所以解除关系应b.getCategorys().remove(c),
		 * 而不是c.getBooks().remove(b)
		 */
		b.getCategorys().remove(c);
	}
	session.delete(c);
	transaction.commit();
	SessionFactoryUtil.closeSession();
}

    /**
 * 删除被控方category
 * @author LJ
 * @Date 2018年10月27日
 * @Time 上午10:54:52
 */
@Test
public void testDelCategory() {
	Category category=new Category();
	category.setCategoryId(2);
	this.del(category);
}

注意:关联关系交于哪一方就由哪一方来解除关系

猜你喜欢

转载自blog.csdn.net/qq_43195035/article/details/83579269