关于两表之间存在一对多、多对一且有控制反转与级联影响的删除

在这里主要说下两张表关联的删除操作(存在一对多、多对一的关系),我在这里只测试了在inverse(true/false),级联cascade(all [save,update,delete,saveorupdate]/ none)的影响下,数据查询方式分别为new方式和get两种状况的影响下的删除操作。

以下我的代码虽然很啰嗦,但是为了能够更明显的看出区别与变化只好出此下策了大笑,如果这还看不明白。我也没办法了。这一篇其实还是值得一看的,尤其是这个

注意:hibernate框架下的通过get方式查询和通过new方式查询是有很大区别的,并且它两的执行机制也是不一样的。


一、项目的所有包及架包


二、数据库信息

表字段信息:


表二字段信息:



三、实体类.hbm.xml配置

boy表:

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE hibernate-mapping PUBLIC     
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"     
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping package="com.yibin.empty">
	<class name="Boy" table="boy">
		<id name="bid">
			<generator class="identity"></generator>
		</id>
		<property name="age"></property>
		<property name="bname" type="string" length="50"></property>
		<set name="girlsfriend" table="girl" inverse="true" cascade="all">
			<key column="bid"></key>
			<one-to-many class="Girl"/>
		</set>
		<!--  inverse="true" -->
	</class>
</hibernate-mapping>

girl表:

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE hibernate-mapping PUBLIC     
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"     
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping package="com.yibin.empty">
	<class name="Girl" table="girl">
		<id name="gid">
			<generator class="identity"></generator>
		</id>
		<property name="gname" type="string" length="50"></property>
		<many-to-one name="boy" column="bid" class="Boy"></many-to-one>
	</class>
</hibernate-mapping>

四、hibernate配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
    <!-- 开始配置我们的工厂,因为在某些方面工厂比较强大 -->
    <session-factory>
    	<!-- 其次配置我们的数据源 -->
    	<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    	<property name="connection.url">jdbc:mysql:///inverse_cascade</property>
    	<property name="connection.username">root</property>
    	<property name="connection.password">123456</property>
    	<!-- 然后在配置我们hibernate独有的一个配置dialect(方言)作用是:为每一种数据库提供适配器,方便转换  -->
    	<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
    	<!-- 根据需求是否需要在控制台输出我们执行的SQL语句 -->
    	<property name="show_sql">true</property>
    	<!-- 根据实体类自动创建表 -->
		<property name="hbm2ddl.auto">update</property>
    	<!-- 接着配置我们的需要操作表的实体类的映射文件配置 -->
    	<mapping resource="com/yibin/empty/Boy.hbm.xml"/>
    	<mapping resource="com/yibin/empty/Girl.hbm.xml"/>
    </session-factory>
    </hibernate-configuration>

五、测试类

package test.yibin.inverse;

import org.hibernate.Session;
import org.junit.Test;

import com.yibin.empty.Boy;
import com.yibin.empty.Girl;
import com.yibin.session.HibernateSessionFactory;

/**
 * 测试两表关联,inverse与cascade对删除操作的影响
 * @author 廖宜彬
 *时间:2018-6-22 20:35:29
 */
public class Testdelete {

	@Test
	/**
	 * 首先测试我们两表关联的删除测试
	 * 具备条件是:控制反转为默认状态,且级联为none(默认状态)
	 * 并且查询方式是通过new对象获取的
	 */
	public void deleteinverse() {
		Session session=HibernateSessionFactory.creSession();
		session.beginTransaction();
		Boy boy=new Boy();
		boy.setBid(7);       //这是通过我们new对象获取到我们该id的一个对象,虽然这个方法也获取到了内容,但是与
							//我们的get方式是有区别的。用new我们是创建了一个对象去接收,该对象是属于游离状态的与从表的关联字段的关系是已经切断了的
							//
		session.delete(boy);
		
		/**		这个操作是执行了的,执行的SQL语句是
		 *  Hibernate: update girl set bid=null where bid=?
		 *	Hibernate: delete from boy where bid=?
		 *
		 *数据库的显示结果是:
		 *主表(boy表)该记录是删除了的,而从表(girl表)的关联字段bid更新为null了
		 */
		
		session.getTransaction().commit();
		HibernateSessionFactory.closesession(session);
	}
	
	@Test
	/**
	 * 再次测试我们两表关联的删除测试
	 * 具备条件是:控制反转为true状态(失去主控权,将主控权交还从表),且级联为none(默认状态)
	 * 并且查询方式仍旧是通过new对象获取的
	 */
	public void deleteinverse2() {
		Session session=HibernateSessionFactory.creSession();
		session.beginTransaction();
		Boy boy=new Boy();
		boy.setBid(8);       
		session.delete(boy);
		
		/**		这个操作是执行了的,执行的SQL语句是,
		 *  Hibernate: delete from boy where bid=?
		 *	
		 *执行时报错了:
		 *Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`inverse_cascade`.`girl`, CONSTRAINT `FK306A9CC2241EE4` FOREIGN KEY (`bid`) REFERENCES `boy` (`bid`))
		 *报错原因很明显,因为两表之间有外键约束所以执行删除操作时失败了
		 *
		 */
		
		session.getTransaction().commit();
		HibernateSessionFactory.closesession(session);
	}
	
	@Test
	/**
	 * 再次测试我们两表关联的删除测试
	 * 具备条件是:控制反转为默认状态(具备主控权),且级联为all(即拥有save,update,saveorupdate,delete)
	 * 并且查询方式仍旧是通过new对象获取的
	 */
	public void deleteinverse3() {
		Session session=HibernateSessionFactory.creSession();
		session.beginTransaction();
		Boy boy=new Boy();
		boy.setBid(8);       
		session.delete(boy);
		
		/**		这个操作是成功的,执行的SQL语句是
		 * Hibernate: update girl set bid=null where bid=?
		 * Hibernate: delete from boy where bid=?
		 * 
		 * 数据库内结果为:
		 * 主表(boy表)该记录是删除了的,而从表(girl表)的关联字段bid更新为null了。由此可见,不论我们是否开启级联都对我们的删除操作五影响
		 */
		session.getTransaction().commit();
		HibernateSessionFactory.closesession(session);
	}
	
	@Test
	/**		
	 * 再次测试我们两表关联的删除测试
	 * 具备条件是:控制反转为true状态,且级联为all(即拥有save,update,saveorupdate,delete)
	 * 并且查询方式仍旧是通过new对象获取的
	 */
	public void deleteinverse4() {
		Session session=HibernateSessionFactory.creSession();
		session.beginTransaction();
		Boy boy=new Boy();
		boy.setBid(9);       
		session.delete(boy);
		
		/**		执行的SQL语句是
		 * Hibernate: delete from boy where bid=?
		 * 执行失败,报错为:
		 * Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`inverse_cascade`.`girl`, CONSTRAINT `FK306A9CC2241EE4` FOREIGN KEY (`bid`) REFERENCES `boy` (`bid`))
		 * 
		 * 报错原因很明显,因为两表之间有外键约束所以执行删除操作时失败了。并且主表失去了主控权
		 */
		session.getTransaction().commit();
		HibernateSessionFactory.closesession(session);
		
		
		/**			两两之间比较进行个小结
		 * 首先,我们的查询都是通过new的方式获取的
		 * 1.不论我们是否开启级联,当我们的控制反转状态是默认状态时,操作是成功的。结果是:
		 * 		我们的主表数据删除成功,从表关联字段数据更新为null。由执行的SQL语句便可以理解
		 * 2.不论我们是否开启级联,当我们的控制反转状态是true时(即主表失去主控权),操作是失败的:
		 * 		原因是,首先我们的主表失去了主控权。但是我们两表之间关联存在着外键约束,所以执行删除操作时无法执行
		 * 
		 */
	}
	
	
	/**************************以下是我查询方式为get的测试********************************************/
	
	@Test
	/**
	 * 具备条件是:控制反转为默认状态,且级联为none(默认状态)
	 * 并且查询方式是通过get对象获取的
	 */
	public void deleteinverseget() {
		Session session=HibernateSessionFactory.creSession();
		session.beginTransaction();
		Boy boy=(Boy)session.get(Boy.class, 9);
		//这是我们通过get的方式获取数据的,该方式获取到的对象是持久状态的,因为get是直接从数据库得到的,所以它们直接的关联联系是存在的
		session.delete(boy);
		
		/**		这个操作是执行了的,执行的SQL语句是
		 *Hibernate: select boy0_.bid as bid0_0_, boy0_.age as age0_0_, boy0_.bname as bname0_0_ from boy boy0_ where boy0_.bid=?
		 *Hibernate: update girl set bid=null where bid=?
		 *Hibernate: delete from boy where bid=?
		 *
		 *数据库的显示结果是:
		 *主表(boy表)该记录是删除了的,而从表(girl表)的关联字段bid更新为null了
		 *
		 *由结果可知我们查询方式get和new的区别,看执行的sql语句便可以理解为什么他们的状态是不一样的,
		 *虽然结果是一样的,但执行的机制却是不同的
		 */
		
		session.getTransaction().commit();
		HibernateSessionFactory.closesession(session);
	}
	
	@Test
	/**
	 * 具备条件是:控制反转为默认状态,且级联为all
	 * 并且查询方式是通过get对象获取的
	 */
	public void deleteinverseget2() {
		Session session=HibernateSessionFactory.creSession();
		session.beginTransaction();
		Boy boy=(Boy)session.get(Boy.class, 10);
		session.delete(boy);
		
		/**		这个操作是执行了的,执行的SQL语句是
		 *Hibernate: select boy0_.bid as bid0_0_, boy0_.age as age0_0_, boy0_.bname as bname0_0_ from boy boy0_ where boy0_.bid=?
		 *Hibernate: select girlsfrien0_.bid as bid0_1_, girlsfrien0_.gid as gid1_, girlsfrien0_.gid as gid1_0_, girlsfrien0_.gname as gname1_0_, girlsfrien0_.bid as bid1_0_ from girl girlsfrien0_ where girlsfrien0_.bid=?
		 *Hibernate: update girl set bid=null where bid=?
		 *Hibernate: delete from girl where gid=?
		 *Hibernate: delete from girl where gid=?
		 *Hibernate: delete from girl where gid=?
		 *Hibernate: delete from boy where bid=?
		 *
		 *数据库的显示结果是:
		 *主表(boy表)该记录删除了的,从表(girl表)的关联字段也删除了
		 *
		 *该操作与我们通过new的方式对比下,你会发现使用get的方式是全删除了,而new的则没有
		 *原因呢,是因为它两的执行机制不一样,new呢是直接先将从表的关联字段更新为null(因为两表之间已经没有什么维护关系了)
		 *而我们的get呢,则是先查询。首先查询我们的主表其次是从表,若存在该数据,则将从表的关联字段更新为null然后在删除与主表有该关系的记录,最后在删除我们的主表
		 */
		
		session.getTransaction().commit();
		HibernateSessionFactory.closesession(session);
	}
	
	@Test
	/**
	 * 具备条件是:控制反转为true状态,且级联为none
	 * 并且查询方式是通过get对象获取的
	 */
	public void deleteinverseget3() {
		Session session=HibernateSessionFactory.creSession();
		session.beginTransaction();
		Boy boy=(Boy)session.get(Boy.class, 11);
		session.delete(boy);
		
		/**		这个操作是执行了的,执行的SQL语句是
		 *Hibernate: select boy0_.bid as bid0_0_, boy0_.age as age0_0_, boy0_.bname as bname0_0_ from boy boy0_ where boy0_.bid=?
		 *Hibernate: delete from boy where bid=?
		 *
		 *
		 *该操作报错了(自然该操作是失败的,数据库数据并未改变):
		 *Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`inverse_cascade`.`girl`, CONSTRAINT `FK306A9CC2241EE4` FOREIGN KEY (`bid`) REFERENCES `boy` (`bid`))
		 *
		 *该操作与我们通过new的方式对比下,你会发现使用get的方式是它的执行机制多了个查询报错原因是一样的
		 */
		
		session.getTransaction().commit();
		HibernateSessionFactory.closesession(session);
	}
	
	@Test
	/**
	 * 具备条件是:控制反转为true状态,且级联为all
	 * 并且查询方式是通过get对象获取的
	 */
	public void deleteinverseget4() {
		Session session=HibernateSessionFactory.creSession();
		session.beginTransaction();
		Boy boy=(Boy)session.get(Boy.class, 11);
		session.delete(boy);
		
		/**		这个操作是执行了的,执行的SQL语句是
		 *Hibernate: select boy0_.bid as bid0_0_, boy0_.age as age0_0_, boy0_.bname as bname0_0_ from boy boy0_ where boy0_.bid=?
		 *Hibernate: select girlsfrien0_.bid as bid0_1_, girlsfrien0_.gid as gid1_, girlsfrien0_.gid as gid1_0_, girlsfrien0_.gname as gname1_0_, girlsfrien0_.bid as bid1_0_ from girl girlsfrien0_ where girlsfrien0_.bid=?
		 *Hibernate: delete from girl where gid=?
		 *Hibernate: delete from girl where gid=?
		 *Hibernate: delete from girl where gid=?
		 *Hibernate: delete from boy where bid=?
		 *
		 *数据库结果为:
		 *主表与从表的关联数据全部删除
		 *
		 *该操作与我们通过new的方式对比下,你会发现使用get的方式操作是成功的,并未报错而new的方式则报错了。
		 *为什么在相同条件下,使用new的方式则报错而使用get的方式则成功呢?原因很简单,还是那句老话。使用new因为两表之间的关系没了
		 *所以删除时有外键约束,而使用get,因为是直接从数据库获取的所以他们两表之间的关系是还有的,自然执行删除是可以的
		 */
		
		session.getTransaction().commit();
		HibernateSessionFactory.closesession(session);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值