Hibernate学习笔记(四)—— 表与表的关系
一、一对多|多对一
1.1 关系表达
【表中的表达】
建表原则:在多的一方创建外键指向一的一方的主键。
【实体中的表达】
客户实体
public class Customer { private Long cust_id; private String cust_name; private String cust_source; private String cust_industry; private String cust_level; private String cust_linkman; private String cust_phone; private String cust_mobile; // 一个客户有多个联系人:客户中应该放有联系人的集合 private Set<LinkMan> linkMans = new HashSet<>(); get/set... }
联系人实体
public class LinkMan { private Long lkm_id; private String lkm_name; private String lkm_gender; private String lkm_phone; private String lkm_mobile; private String lkm_email; private String lkm_qq; private String lkm_position; private String lkm_memo; // Hibernate是一个ORM框架:在关系型数据库中描述表与表之间的关系,使用的是外键。开发语言使用的是Java,面向对象的 private Customer customer;
get/set...
}
【配置文件中的表达】
客户的映射
<?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 package="cn.itcast.domain" > <class name="Customer" table="cst_customer" > <id name="cust_id" > <generator class="native"></generator> </id> <property name="cust_name" column="cust_name" ></property> <property name="cust_source" column="cust_source" ></property> <property name="cust_industry" column="cust_industry" ></property> <property name="cust_level" column="cust_level" ></property> <property name="cust_linkman" column="cust_linkman" ></property> <property name="cust_phone" column="cust_phone" ></property> <property name="cust_mobile" column="cust_mobile" ></property> <!-- 配置关联对象 --> <!-- name属性:多的一方集合的属性名称 --> <set name="linkMans"> <!-- column属性:多的一方外键的名称 --> <key column="lkm_cust_id"></key> <!-- 多的一方类的全路径,如果前面的package中设置了包名,这里填类名即可 --> <one-to-many class="LinkMan"/> </set> </class> </hibernate-mapping>
联系人的映射
<?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 package="cn.itcast.domain" > <class name="LinkMan" table="cst_linkman" > <id name="lkm_id" > <generator class="native"></generator> </id> <property name="lkm_name" column="lkm_name" ></property> <property name="lkm_gender" column="lkm_gender" ></property> <property name="lkm_phone" column="lkm_phone" ></property> <property name="lkm_mobile" column="lkm_mobile" ></property> <property name="lkm_email" column="lkm_email" ></property> <property name="lkm_qq" column="lkm_qq" ></property> <property name="lkm_position" column="lkm_position" ></property> <property name="lkm_memo" column="lkm_memo" ></property> <!-- 配置关联对象 --> <!-- name:一的一方的对象的名称 class:一的一方类的全路径 column:表中外键的名称 --> <many-to-one name="customer" class="Customer" column="lkm_cust_id"/> </class> </hibernate-mapping>
1.2 测试代码
- 保存
// 保存一个客户和两个联系人 @Test public void testSave() throws Exception { // 获得session Session session = HibernateUtils.openSession(); // 开启事务 Transaction tx = session.beginTransaction(); // 创建一个客户 Customer customer = new Customer(); customer.setCust_name("李总"); // 创建两个联系人 LinkMan linkMan1 = new LinkMan(); linkMan1.setLkm_name("张秘书"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("王助理"); // 表达一对多,客户下有多个联系人 customer.getLinkMans().add(linkMan1); customer.getLinkMans().add(linkMan2); // 表达多对一,联系人属于哪个客户 linkMan1.setCustomer(customer); linkMan2.setCustomer(customer); session.save(customer); session.save(linkMan1); session.save(linkMan2); // 提交事务 tx.commit(); // 关闭资源 session.close(); }
- 增加
// 为客户增加联系人 @Test public void testAdd() throws Exception { // 获得session Session session = HibernateUtils.openSession(); // 开启事务 Transaction tx = session.beginTransaction(); // 获得要操作的客户对象 Customer customer = session.get(Customer.class, 1l); // 创建联系人 LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("赵秘书"); // 将联系人添加到客户中 customer.getLinkMans().add(linkMan); // 将客户设置到联系人中 linkMan.setCustomer(customer); // 执行保存 session.save(linkMan); tx.commit(); session.close(); }
- 删除
// 为客户删除联系人 @Test public void testDelete() throws Exception { // 获得session Session session = HibernateUtils.openSession(); // 开启事务 Transaction tx = session.beginTransaction(); // 获得要操作的客户对象 Customer customer = session.get(Customer.class, 1l); // 获得要移除的联系人 LinkMan linkMan = session.get(LinkMan.class, 2l); // 将联系人从客户集合中移除 customer.getLinkMans().remove(linkMan); linkMan.setCustomer(null); tx.commit(); session.close(); }
1.3 级联保存或更新
级联操作是指当主控方执行保存、更新或者删除操作时,其关联的对象(被控方)也执行相同的操作。在映射文件中通过对cascade属性的设置来控制是否对关联对象采用级联操作,级联操作对各种关联关系都是有效的。
级联是有方向性的,所谓的方向性指的是,在保存一的一方级联多的一方,和在保存多的一方级联一的一方。
【保存客户级联联系人】
首先要确定我们要保存的主控方是哪一方,我们要保存客户,所以客户是主控方,那么需要在客户的映射文件中(Customer.hbm.xml)进行如下配置:
<!-- 配置关联对象 --> <!-- name属性:多的一方集合的属性名称 --> <set name="linkMans" cascade="save-update"> <!-- column属性:多的一方外键的名称 --> <key column="lkm_cust_id"></key> <!-- 多的一方类的全路径,如果前面的package中设置了包名,这里填类名即可 --> <one-to-many class="LinkMan"/> </set>
编写测试代码:
// 级联保存:只保存一边的问题 // 级联是有方向性的,保存客户同时级联客户的联系人 // 在Customer.hbm.xml的<set>标签上配置cascade="save-update" @Test public void testCascade() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 创建一个客户 Customer customer = new Customer(); customer.setCust_name("刘总"); // 创建联系人 LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("王秘书"); // 建立关系 customer.getLinkMans().add(linkMan); linkMan.setCustomer(customer); session.save(customer); tx.commit(); session.close(); }
【保存联系人级联客户】
同样我们需要确定主控方,现在我们的主控方是联系人。所以需要在联系人的映射文件中(LinkMan.hbm.xml)进行配置:
<!-- 配置关联对象 --> <!-- name:一的一方的对象的名称 class:一的一方类的全路径 column:表中外键的名称 --> <many-to-one name="customer" cascade="save-update" class="Customer" column="lkm_cust_id"/>
测试代码:
// 级联保存:只保存一边的问题 // 级联是有方向性的,保存联系人同时级联客户 // 在LinkMan.hbm.xml的<many-to-one>标签上配置cascade="save-update" @Test public void testCascade2() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 创建客户 Customer customer = new Customer(); customer.setCust_name("张总"); // 创建联系人 LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("柳助理"); // 建立关系 customer.getLinkMans().add(linkMan); linkMan.setCustomer(customer); session.save(linkMan); tx.commit(); session.close(); }
到这我们已经可以看到级联保存或更新的效果了。那么我们维护的时候都是双向的关系维护。这种关系到底表述的是什么含义呢?我们可以通过下面的测试来更进一步了解关系的维护(对象导航)的含义。
1.4 测试对象导航的问题
我们所说的对象导航其实就是在维护双方的关系。
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
这种关系有什么用途呢?我们可以通过下面的测试来更进一步学习Hibernate。
我们在客户和联系人端都配置了cascade="save-update",然后进行如下的关系设置。会产生什么样的效果呢?
1 // 测试对象导航和级联操作 2 @Test 3 public void testCascade3() throws Exception { 4 Session session = HibernateUtils.openSession(); 5 Transaction tx = session.beginTransaction(); 6 7 // 创建一个客户 8 Customer customer = new Customer(); 9 customer.setCust_name("赵总"); 10 11 // 创建三个联系人 12 LinkMan linkMan1 = new LinkMan(); 13 linkMan1.setLkm_name("李秘书"); 14 LinkMan linkMan2 = new LinkMan(); 15 linkMan2.setLkm_name("王秘书"); 16 LinkMan linkMan3 = new LinkMan(); 17 linkMan3.setLkm_name("张助理"); 18 19 // 建立关系 20 linkMan1.setCustomer(customer); 21 customer.getLinkMans().add(linkMan2); 22 customer.getLinkMans().add(linkMan3); 23 24 // 条件是双方都设置了cascade="save-update" 25 session.save(linkMan1); // 数据库中有几条记录?发送了几条insert语句? 4条 26 // session.save(customer); // 发送了几条insert语句? 3条 27 // session.save(linkMan2); // 发送了几条insert语句? 1条 28 29 tx.commit(); 30 session.close(); 31 }
我们在执行第25行代码时,问会执行几条insert语句?其实发现会有4条insert语句,因为联系人1关联了客户,客户又关联了联系人2和联系人3,所以当保存联系人1的时候,联系人1是可以进入到数据库的,它关联的客户也是会进入到数据库的(因为联系人一端配置了级联),那么客户进入到数据库以后,联系人2和联系人3也同样会进入到数据库(因为客户一端配置了级联),所以会有4条insert语句。
我们在执行26行的时候,问会有几条insert语句?这时我们保存的客户对象关联了联系人2和联系人3,那么客户在进入数据库的时候,联系人2和联系人3也会进入到数据库,所以是3条insert语句。
同理我们执行27行代码的时候,只会执行1条insert语句。因为联系人2会保存到数据库,但是联系人2没有对客户建立关系,所以客户不会保存到数据库。
1.5 Hibernate的级联删除
我们之前学习过级联保存或更新,那么再来看级联删除也就不难理解了,级联删除也是有方向性的,删除客户同时级联删除联系人,也可以删除联系人同时级联删除客户(这种需求很少)。
原来JDBC中删除客户和联系人的时候,如果有外键的关系是不可以删除的,但是现在我们使用了Hibernate,其实Hibernate可以实现这样的功能,但是不会删除客户的同时删除联系人,默认情况下Hibernate会怎么做呢?我们来看下面的测试:
// 删除有级联关系的对象:(默认情况:先将关联对象的外键置为null,再删除) @Test public void demo5() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); Customer customer = session.get(Customer.class, 1l); session.delete(customer); tx.commit(); session.close(); }
默认情况下如果客户下面还有联系人,Hibernate会将联系人的外键置为null,然后区删除客户。那么其实有的时候我们需要删除客户的时候,同时将客户关联的联系人一起删除。这个时候我们就需要使用Hibernate的级联删除操作了。
【删除客户的同时删除客户的联系人】
确定删除的主控方是客户,所以需要在客户端(Customer.hbm.xml)配置:
<!-- 配置关联对象 --> <!-- name属性:多的一方集合的属性名称 --> <set name="linkMans" cascade="delete"> <!-- column属性:多的一方外键的名称 --> <key column="lkm_cust_id"></key> <!-- 多的一方类的全路径,如果前面的package中设置了包名,这里填类名即可 --> <one-to-many class="LinkMan"/> </set>
如果还想有之前的级联保存或更新,同时还想有级联删除,那么我们可以进行如下的配置:
<!-- 配置关联对象 --> <!-- name属性:多的一方集合的属性名称 --> <set name="linkMans" cascade="delete,save-update"> <!-- column属性:多的一方外键的名称 --> <key column="lkm_cust_id"></key> <!-- 多的一方类的全路径,如果前面的package中设置了包名,这里填类名即可 --> <one-to-many class="LinkMan"/> </set>
测试代码:
// 级联删除:级联删除有方向性 // 删除客户的同时删除联系人 // 在Customer.hbm.xml的<set>标签上配置cascade="delete" @Test public void demo6() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 级联删除:必须是先查询再删除 // 因为查询到客户,这个时候客户的联系人集合就会有数据 Customer customer = session.get(Customer.class, 7l); session.delete(customer); tx.commit(); session.close(); }
【删除联系人的同时删除客户】
这时候我们删除的是联系人,那么联系人就是主控方,需要在联系人端(LinkMan.hbm.xml)配置:
<!-- 配置关联对象 --> <!-- name:一的一方的对象的名称 class:一的一方类的全路径 column:表中外键的名称 --> <many-to-one name="customer" cascade="delete" class="Customer" column="lkm_cust_id"/>
如果既要保存或更新有级联操作,又要有级联删除的功能,也可以如下配置:
<!-- 配置关联对象 --> <!-- name:一的一方的对象的名称 class:一的一方类的全路径 column:表中外键的名称 --> <many-to-one name="customer" cascade="delete,save-update" class="Customer" column="lkm_cust_id"/>
测试代码:
// 级联删除:级联删除有方向性 // 删除联系人的同时删除客户 // 在LinkMan.hbm.xml中的<many-to-one>标签上配置cascade="delete" @Test public void demo7() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 级联删除:必须是先查询再删除 LinkMan linkMan = session.get(LinkMan.class, 4l); session.delete(linkMan); tx.commit(); session.close(); }
1.6 双向关联产生多余的SQL语句
【客户表】
【联系人表】
有时候我们需要进行如下操作:将2号联系人关联给2号客户,也就是将2号李秘书这个联系人关联给2号刘总这个客户。
编写修改2号客户关联的联系人的代码:
// 将2号联系人关联的客户改为2号客户 @Test public void demo8() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); Customer customer = session.get(Customer.class, 2l); LinkMan linkMan = session.get(LinkMan.class, 2l); linkMan.setCustomer(customer); customer.getLinkMans().add(linkMan); tx.commit(); session.close(); }
运行上述代码,控制台输出如下内容:
我们发现执行了两次update语句,其实这两个update都是修改了外键的操作,那么为什么发送两次呢?我们来分析一下产生这个问题的原因:
我们已经分析过了,因为双向维护了关系,而且持久态对象可以自动更新数据库,更新客户的时候会修改一次外键,更新联系人的时候同样会修改一次外键。这样就会产生多余的SQL。问题产生了,我们该如何解决呢?
其实解决的办法很简单,只需要一方放弃外键维护权即可。也就是说关系不是双方维护的,只需要交给某一方去维护就可以了。通常我们都是交给多的一方去维护。为什么呢?因为多的一方才是维护关系最好的地方。举个例子,一个老师对应多个学生,一个学生对应一个老师,这时典型的一对多。一个老师如果要记住所有学生的名字很难,但如果让每个学生记住老师的名字应该不难。其实就是这个道理。所有在一对多中,一的一方都会放弃外键的维护权(关系的维护);
这个时候如果想让一的一方放弃外键的维护权,只需要进行如下配置即可:
<!-- 配置关联对象 --> <!-- name属性:多的一方集合的属性名称 --> <set name="linkMans" cascade="save-update" inverse="true"> <!-- column属性:多的一方外键的名称 --> <key column="lkm_cust_id"></key> <!-- 多的一方类的全路径,如果前面的package中设置了包名,这里填类名即可 --> <one-to-many class="LinkMan"/> </set>
inverse的默认值是false,代表不放弃外键的维护权,配置值为true,代表放弃了外键的维护权。这个时候再来执行之前的操作:
这时候就不会出现上述问题了,不会产生多余的SQL了(因为一的一方已经放弃了外键的维护权)。
1.7 区分cascade和inverse
// cascade和inverse // cascade强调的是操作一个对象的时候,是否操作其关联的对象 // inverse强调的是外键的维护权 @Test public void demo9() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("王总"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("赵秘书"); // 在Customer.hbm.xml的<set>标签上配置cascade="save-update" inverse="true" customer.getLinkMans().add(linkMan); session.save(customer); tx.commit(); session.close(); }
这时候我们会发现,如果在<set>标签上配置cascade="save-update" inverse="true",那么执行保存客户的操作时,会发现客户和联系人都进入到数据库了,但是没有外键。是因为配置了cascade="save-update"所以客户关联的联系人会进入到数据库中,但是客户一端放弃了外键的维护权(inverse="true"),所以联系人插入到数据库以后是没有外键的。
二、多对多
2.1 关系表达
【表中的表达】
【对象中的表达】
用户实体
public class User { private Long user_id; private String user_code; private String user_name; private String user_password; private String user_state; // 用户所属的角色集合 private Set<Role> roles = new HashSet<>();
get/set... }
角色实体
public class Role { private Long role_id; private String role_name; private String role_memo; // 一个角色包含多个用户 private Set<User> users = new HashSet<>();
get/set... }
【配置文件中的表达】
用户的映射——User.hbm.xml
<?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 package="cn.itcast.domain" > <class name="User" table="sys_user" > <id name="user_id" > <generator class="native"></generator> </id> <property name="user_code"/> <property name="user_name"/> <property name="user_password"/> <property name="user_state"/> <!-- 多对多关系表达 --> <!-- name:集合属性名 table:配置中间表名 --> <set name="roles" table="sys_user_role"> <!-- column:外键,别人引用"我"的外键列名 --> <key column="user_id"></key> <!-- class:我与哪个类是多对多关系 column:外键.我引用别人的外键列名 --> <many-to-many class="Role" column="role_id"></many-to-many> </set> </class> </hibernate-mapping>
角色的映射——Role.hbm.xml
<?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 package="cn.itcast.domain" > <class name="Role" table="sys_role" > <id name="role_id" > <generator class="native"></generator> </id> <property name="role_name"/> <property name="role_memo"/> <!-- 多对多关系表达 --> <!-- name:集合属性名 table:配置中间表名 --> <set name="users" table="sys_user_role"> <!-- column:外键,别人引用"我"的外键列名 --> <key column="role_id"></key> <!-- class:我与哪个类是多对多关系 column:外键.我引用别人的外键列名 --> <many-to-many class="User" column="user_id"></many-to-many> </set> </class> </hibernate-mapping>
在hibernate.cfg.xml中加入映射文件
<mapping resource="cn/itcast/domain/User.hbm.xml" /> <mapping resource="cn/itcast/domain/Role.hbm.xml" />
2.2 测试方法
- 保存
// 保存用户及角色 @Test public void fun1() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 创建两个User User user1 = new User(); user1.setUser_name("张三"); User user2 = new User(); user2.setUser_name("李四"); // 创建两个Role Role role1 = new Role(); role1.setRole_name("保洁"); Role role2 = new Role(); role2.setRole_name("保安"); // 用户表达关系 user1.getRoles().add(role1); user1.getRoles().add(role2); user2.getRoles().add(role2); // 角色表达关系 role1.getUsers().add(user1); role2.getUsers().add(user1); role2.getUsers().add(user2); // 调用save方法一次保存 session.save(user1); session.save(user2); session.save(role1); session.save(role2); tx.commit(); session.close(); }
执行上述代码时,我们发现报错了:
【错误原因分析】
映射文件中有一个inverse属性,不配置时默认为false,即要维护关系。这里两方关系都设置了{user1.getRoles().add(role1);role1.getUsers().add(user1);},从配置上讲,这两方都没放弃维护。多对多维护关系的手段是向中间表(sys_user_role)插入记录,如果要表达1号用户的角色是1号,那么中间表就会插入1-1记录。现在的情况是两方都默认维护关系,role在维护关系的时候,表达1-1,会在中间表插入1-1记录;user在维护关系的时候,也要往中间表插入数据,这时候user又要插入1-1记录。中间表往往是这两个id共同作为主键的,这两个1-1就会出现主键重复。
之前的一对多两方都维护关系,却没发生异常,是因为它们维护关系,就是修改了外键字段,不存在向中间表插入记录,所以修改两次是没有问题的,至少不会报错,虽然效率会低点。而多对多维护关系是向中间表插入记录,两方都维护的时候,就会插入两条一样的记录,就会产生主键重复。
【解决方案】
方法一:映射文件不改,从代码上来讲,只要一方不表达关系即可,这样在保存的时候,因为代码上并没有表达关系的逻辑,就不会给你操作了。这里我们可以让role的一方不表达关系,在代码上把相关代码注释,此时方法就可执行成功
方法二:代码不改,在一方的映射文件中修改inverse为true,让它放弃维护关系。这里修改Role.hbm.xml
【结论】
在多对多的保存操作中,如果进行了双向维护关系,就必须有一方放弃外键维护权。一般由被动方放弃,用户主动选择角色,角色是被选择的,所以一般角色要放弃外键维护权。但如果只进行单向维护关系,那么就不需要放弃外键维护权了。
2.3 级联保存或更新
【保存用户级联角色】
保存的主控方是用户,需要在用户一端(User.hbm,xml)配置
测试代码:
// 保存用户级联角色 @Test public void fun2() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 创建两个User User user1 = new User(); user1.setUser_name("刘备"); User user2 = new User(); user2.setUser_name("关羽"); // 创建三个角色 Role role1 = new Role(); role1.setRole_name("人事管理"); Role role2 = new Role(); role2.setRole_name("行政管理"); Role role3 = new Role(); role3.setRole_name("财务管理"); // 建立关系:如果建立了双向的关系,一定要有一方放弃外键维护权 user1.getRoles().add(role1); user1.getRoles().add(role2); user2.getRoles().add(role3); user2.getRoles().add(role2); role1.getUsers().add(user1); role2.getUsers().add(user1); role2.getUsers().add(user2); role3.getUsers().add(user2); session.save(user1); session.save(user2); /*session.save(role1); session.save(role2); session.save(role3);*/ tx.commit(); }
【保存角色级联用户】
保存的主控方是角色,需要在角色一端配置:
测试代码:
// 保存角色级联用户 @Test public void fun2() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 创建两个User User user1 = new User(); user1.setUser_name("刘备"); User user2 = new User(); user2.setUser_name("关羽"); // 创建三个角色 Role role1 = new Role(); role1.setRole_name("人事管理"); Role role2 = new Role(); role2.setRole_name("行政管理"); Role role3 = new Role(); role3.setRole_name("财务管理"); // 建立关系:如果建立了双向的关系,一定要有一方放弃外键维护权 user1.getRoles().add(role1); user1.getRoles().add(role2); user2.getRoles().add(role3); user2.getRoles().add(role2); role1.getUsers().add(user1); role2.getUsers().add(user1); role2.getUsers().add(user2); role3.getUsers().add(user2); /*session.save(user1); session.save(user2);*/ session.save(role1); session.save(role2); session.save(role3); tx.commit(); }
2.4 级联删除(了解)
在多对多中级联删除是不会使用的,因为我们不会有这类的需求,比如删除用户,将用户关联的角色一起删除,或者删除角色的时候将用户删除掉,这时不合理的。但是级联删除的功能Hibernate已经提供了此功能,所以我们只需要了解即可。
【删除用户级联角色】
主控方是用户,所以需要在用户端配置
测试代码:
// 级联删除:删除用户,级联删除角色 @Test public void fun3() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); User user = session.get(User.class, 1l); session.delete(user); tx.commit(); session.close(); }
2.5 多对多的其他操作
- 删除某个用户的角色
// 将1号用户的1号角色去掉 @Test public void fun4() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 查询1号用户 User user = session.get(User.class, 1l); // 查询1号角色 Role role = session.get(Role.class, 1l); // 操作集合 相当于操作数据库 user.getRoles().remove(role); tx.commit(); }
- 将某个用户的角色改选
// 将1号用户的2号角色去掉,改为3号角色 @Test public void fun5() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 查询1号用户 User user = session.get(User.class, 1l); // 查询2号角色 Role role1 = session.get(Role.class, 2l); // 查询3号角色 Role role2 = session.get(Role.class, 3l); user.getRoles().remove(role1); user.getRoles().add(role2); tx.commit(); }
- 给某个用户添加新角色
// 给1号用户添加2号角色 @Test public void fun6() throws Exception { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 查询1号用户 User user = session.get(User.class, 1l); // 查询2号角色 Role role = session.get(Role.class, 2l); user.getRoles().add(role); tx.commit(); }