hibernate中有关多表的级联增删改查

还是以User 和 Dog这两张表为例:

多表增:

分三种情况--主表增(单表增)/从表增/同时增

同时增加一个user对象和一个dog对象,且dog属于user,这时候这么写:

@org.junit.Test
	public void test() {
		Session sesission = SessionFactoryUtils.getSessionFactory().getCurrentSession();
		Transaction tx = sesission.beginTransaction();
		User user = new User();
		user.setUsername("xixixi");
		Dog dog = new Dog();
		dog.setDogname("哈士奇");
		user.getDogs().add(dog);
		dog.setDogmaster(user);
		//sesission.save(user);用这一句也行,它和下面的save(dog)都可以实现此目的
		sesission.save(dog);
		tx.commit();
	}

现在新增一个dog对象,然后属于ID为1的用户,代码如下:

@org.junit.Test
	public void test3() {
		Session sesission = SessionFactoryUtils.getSessionFactory().getCurrentSession();
		Transaction tx = sesission.beginTransaction();
		User user = sesission.get(User.class,Integer.parseInt("1"));
		Dog dog = new Dog();
		dog.setDogname("wangwang");
		
		dog.setDogmaster(user);
		user.getDogs().add(dog);//这行和上一行最好都写上,这样才能正确添加他们之间的关系,如果上行不写,结果是往数据库插入的dog没有对应的master
		sesission.update(user);//或者save(dog)也行
		
		tx.commit();
	}

新增用户对象就是单表没什么好说的。


多表更新:

因为主表有关的就是id,而id是不可能更新的,所以没它事儿。只剩下从表更新,从表更新就是单表更新,如下:

	@org.junit.Test
	public void test2() {
		Session sesission = SessionFactoryUtils.getSessionFactory().getCurrentSession();
		Transaction tx = sesission.beginTransaction();
		User user = sesission.get(User.class,Integer.parseInt("1"));
		Dog dog = sesission.get(Dog.class, Integer.parseInt("2"));
		dog.setDogmaster(user);
		sesission.update(dog);
		tx.commit();
	}

结果:

Hibernate: 
    select
        user0_.id as id1_1_0_,
        user0_.username as username2_1_0_,
        user0_.password as password3_1_0_ 
    from
        user user0_ 
    where
        user0_.id=?
Hibernate: 
    select
        dog0_.dogid as dogid1_0_0_,
        dog0_.dogname as dogname2_0_0_,
        dog0_.dogcolor as dogcolor3_0_0_,
        dog0_.dogage as dogage4_0_0_,
        dog0_.dogmaster as dogmaste5_0_0_ 
    from
        dog dog0_ 
    where
        dog0_.dogid=?
Hibernate: 
    update
        dog 
    set
        dogname=?,
        dogcolor=?,
        dogage=?,
        dogmaster=? 
    where
        dogid=?

多表删除:----删除从表相当于单表删除/删除主表记录(配置了save-update,delete)/删除主表记录(没配置delete)

删除主表记录(配置了save-update,delete)

@org.junit.Test
	public void test4() {
		Session session = SessionFactoryUtils.getSessionFactory().getCurrentSession();
		Transaction tx = session.beginTransaction();
		User user = session.get(User.class, Integer.parseInt("3"));
		session.delete(user);//user对象对应着两个dog对象
		
		tx.commit();
	}

结果:

Hibernate: 
    select
        user0_.id as id1_1_0_,
        user0_.username as username2_1_0_,
        user0_.password as password3_1_0_ 
    from
        user user0_ 
    where
        user0_.id=?
Hibernate: 
    select
        dogs0_.dogmaster as dogmaste5_0_0_,
        dogs0_.dogid as dogid1_0_0_,
        dogs0_.dogid as dogid1_0_1_,
        dogs0_.dogname as dogname2_0_1_,
        dogs0_.dogcolor as dogcolor3_0_1_,
        dogs0_.dogage as dogage4_0_1_,
        dogs0_.dogmaster as dogmaste5_0_1_ 
    from
        dog dogs0_ 
    where
        dogs0_.dogmaster=?
Hibernate: 
    delete 
    from
        dog 
    where
        dogid=?
Hibernate: 
    delete 
    from
        dog 
    where
        dogid=?
Hibernate: 
    delete 
    from
        user 
    where
        id=?

分析:hibernate先查询user这条记录,再查询它对应的所有dog对象并将这些对象封装到一个个对象中,然后开始一条条删除dog对象,最后删除user。

ps:这里提一点就是容易忽视的inverse,我们在使用级联删除的时候如果没有配置inverse属性,那么主表会去维护外键,(可能是因为知道自己即将删除故先去将从表中对应字段变为null),所以会执行一个update语句,如果这时候那个外键子段恰巧不能为null,那么你的删除功能也就凉了~所以最好配上inverse=true.配上结果图:

Hibernate: 
    select
        user0_.id as id1_1_0_,
        user0_.username as username2_1_0_,
        user0_.password as password3_1_0_ 
    from
        user user0_ 
    where
        user0_.id=?
Hibernate: 
    select
        dogs0_.dogmaster as dogmaste5_0_0_,
        dogs0_.dogid as dogid1_0_0_,
        dogs0_.dogid as dogid1_0_1_,
        dogs0_.dogname as dogname2_0_1_,
        dogs0_.dogcolor as dogcolor3_0_1_,
        dogs0_.dogage as dogage4_0_1_,
        dogs0_.dogmaster as dogmaste5_0_1_ 
    from
        dog dogs0_ 
    where
        dogs0_.dogmaster=?
Hibernate: 
    update
        dog 
    set
        dogmaster=null //这里就是那个执行置空的语句
    where
        dogmaster=?
Hibernate: 
    delete 
    from
        dog 
    where
        dogid=?
Hibernate: 
    delete 
    from
        user 
    where
        id=?

ps:中途执行session.delete(user)的时候报过个异常:

javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of com.dimples.dao.Dog.dogage 	                                                                 at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.ja
这是因为数据库会去查这个user对应哪些dog,然后封装到实体中。而我的这个dog记录的dogage是null,但在Dog类中我定义的dogage属性是int类型的,导致查出来以后用set方法无法封装,因为你无法将一个null值set到int变量中,所以报这个错,将数据库里值改为0或者直接改变Dog类的dogage属性为Integer。


删除主表记录(没配置delete)

不配置delete的时候去执行上面的语句,会得到另一种异常:could not excute statement,为什么不报刚才那个错了呢,原因就是你配置了delete以后,hibernate再去查询user下面有没有dog的时候用的是count,所以根本不存在封装这一步,也就不会报那个错,如果得到的结果大于等于1,自然是提示could not excute statement,如果等于0,那么会执行delete操作。


猜你喜欢

转载自blog.csdn.net/dimples_qian/article/details/80874508