还是以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操作。