Hibernate的基础入门--笔记(三)
1.关于多表设计的知识回顾
两张表之间有几种关系:
一对多,多对一
一对一,多对多
关于表之间的关系要明确的事情:
一对多和多对一如果说是一种的话,那应该叫:双向一对多
举例:
用户和订单
一个用户可以有多个订单
多个订单属于一个用户
他们之间的关系是:双向一对多
用户和订单之间的关系: 是一对
订单和用户之间的关系: 是多对一
2.Hibernate中的一对多关系映射及操作
前提:
学习hibernate中多表映射应该遵循步骤:
1.明确表之间确实是如你所想的关系
2.在数据库中是SQL语句建立他们的之间的关系
3.在实体类中描述两个实体之间的关系
4.在映射配置文件中建立他们的关系映射
示例:
使用CRM系统中的客户表和联系人表来建立关系



1 <hibernate-mapping package="com.gcl.domain"> 2 <class name="LinkMan" table="cst_linkman"> 3 <id name="lkmId" column="lkm_id"> 4 <generator class="native"></generator> 5 </id> 6 <property name="lkmName" column="lkm_name"></property> 7 <property name="lkmGender" column="lkm_gender"></property> 8 <property name="lkmPhone" column="lkm_phone"></property> 9 <property name="lkmMobile" column="lkm_mobile"></property> 10 <property name="lkmEmail" column="lkm_email"></property> 11 <property name="lkmPosition" column="lkm_position"></property> 12 <property name="lkmMemo" column="lkm_memo"></property> 13 <!-- 多对一关系映射 14 涉及的标签: 15 many-to-one 16 作用:用于映射多对一的关系 17 属性: 18 name:指的实体类中引用客户实体的属性名称 19 column:指的是从表中外键字段的名称 20 class:指定的是属性所对应的实体类
cascade:配置级联操作 属性取值:save_update级联保存更新
21 --> 22 <many-to-one name="customer" class="Customer" column="lkm_cust_id"></many-to-one> 23 24 </class> 25 </hibernate-mapping>
1 <!DOCTYPE hibernate-mapping PUBLIC 2 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping package="com.gcl.domain"> 5 <class name="Customer" table="cst_customer"> 6 <id name="custId" column="cust_id"> 7 <generator class="native"></generator> 8 </id> 9 <property name="custName" column="cust_name"></property> 10 <property name="custIndustry" column="cust_industry"></property> 11 <property name="custSource" column="cust_source"></property> 12 <property name="custLevel" column="cust_level"></property> 13 <property name="custAddress" column="cust_address"></property> 14 <property name="custPhone" column="cust_phone"></property> 15 <!-- 一对多关系映射: 16 涉及的标签: 17 set: 18 作用:用于映射set集合属性。 19 属性: 20 name:指定集合属性的名称 21 table:指定集合元素所对应的表。在一对多时,table属性可以不写。 22 one-to-many: 23 作用:指定当前映射文件所对应的实体和集合元素之间的关系是一对多。 24 属性: 25 class:指定集合元素所对应的实体类名称 26 key: 27 作用:用于映射外键的。 28 属性: 29 column:指定外键字段名称。 30 31 --> 32 <set name="linkmans" table="cst_linkman"> 33 <key column="lkm_cust_id"/> 34 <one-to-many class="LinkMan"/> 35 </set> 36 </class> 37 </hibernate-mapping>
操作:
单向多对一:
1 /** 2 * 单向多对一操作: 3 * 我们有客户,不知道客户下有多少联系人 4 * 我们有联系人,知道联系人属于哪个客户 5 * @author zhy 6 * 7 */ 8 public class HibernateDemo1 { 9 10 /** 11 * 需求: 12 * 保存客户和联系人 13 * 要求: 14 * 创建一个客户 15 * 创建一个联系人 16 * 建立联系人和客户的单向多对一关联关系。 17 * 先保存联系人,再保存客户 18 * 问题: 19 * 保存时,产生了3条sql语句。其中2条是insert,1条update 20 * 实际我们保存2个实体,应该只有2条insert语句。 21 * 原因: 22 * 由于快照机制的存在,在保存联系人时,会产生联系人中所有数据的快照,其中也包含引用的客户部分。 23 * 再保存客户时,客户产生自己的一级缓存和快照。 24 * 解决办法: 25 * 保存原则:先保存主表数据,再保存从表数据。 26 */ 27 @Test 28 public void test1(){ 29 //创建两个实体 30 Customer c = new Customer();//临时态对象 31 c.setCustName("修正w"); 32 c.setCustIndustry("医药制造"); 33 c.setCustSource("网络"); 34 c.setCustLevel("VIP"); 35 c.setCustAddress("昌平区"); 36 c.setCustPhone("010-43853487"); 37 38 LinkMan l = new LinkMan();//临时态 39 l.setLkmName("修正联系人1w"); 40 l.setLkmGender("male"); 41 l.setLkmMobile("13811111111"); 42 l.setLkmPhone("010-34854832"); 43 l.setLkmEmail("332432324@qq.com"); 44 l.setLkmPosition("采购员"); 45 l.setLkmMemo("不好接触"); 46 47 //建立他们之间单向多对一关系 48 l.setCustomer(c); 49 50 Session s = HibernateUtil.getCurrentSession(); 51 Transaction tx = s.beginTransaction(); 52 //保存 53 // s.save(l);//临时态转成了持久态 54 // s.save(c);//临时态转成了持久态 55 56 //解决问题 57 s.save(c);//临时态转成了持久态 58 s.save(l);//临时态转成了持久态 59 60 tx.commit(); 61 } 62 63 /** 64 * 需求: 65 * 创建一个新的客户对象 66 * 查询一个id为1的联系人 67 * 给id为1的联系人分配这个新的客户对象 68 * 更新联系人 69 * 问题: 70 * 在更新一个实体时,如果该实体关联了一个临时态对象,更新时会报错。 71 * 解决办法: 72 * 级联保存更新. 73 * 级联:当我们做一个操作时,通过配置的方式可以让hibernate做多个操作。 74 * 配置的方式: 75 * 要操作谁,就找谁的配置文件。 76 * 要级联操作谁,就找谁的配置 77 * 使用的属性: 78 * cascade:配置级联操作 79 * 属性的取值: 80 * save-update:级联保存更新 81 * */ 82 @Test 83 public void test2(){ 84 //创建客户对象 85 Customer c = new Customer();//临时态对象 86 c.setCustName("修正b"); 87 c.setCustIndustry("医药制造"); 88 c.setCustSource("网络"); 89 c.setCustLevel("VIP"); 90 c.setCustAddress("昌平区"); 91 c.setCustPhone("010-43853487"); 92 93 Session s = HibernateUtil.getCurrentSession(); 94 Transaction tx = s.beginTransaction(); 95 //查询id为1的联系人 96 LinkMan man1 = s.get(LinkMan.class, 1L); 97 //为man1设置新的客户 98 man1.setCustomer(c); 99 //更新联系人 100 s.update(man1); 101 tx.commit(); 102 } 103 104 105 }
双向一对多:
1 /** 2 * 双向一对多操作: 3 * 我们有客户,知道客户下有多少联系人 4 * 我们有联系人,知道联系人属于哪个客户 5 * @author zhy 6 * 7 */ 8 public class HibernateDemo2 { 9 10 /** 11 * 需求: 12 * 保存客户和联系人 13 * 要求: 14 * 创建一个客户 15 * 创建一个联系人 16 * 建立联系人和客户的双向一对多关系 17 * 先保存客户,再保存联系人(符合保存原则:先保存主表,再保存从表) 18 * 问题: 19 * 当我们建立了双向关联关系之后,就算是先保存主表,再保存从表,仍然会出现3条语句。其中两条insert和1条update. 20 * 而实际我们只需要2条insert语句。 21 * 它和单向多对一的保存操作,先保存从表,再保存主表所产生的update语句不一样。 22 * 单向多对一时,update语句是全字段更新。 23 * 双向一对多时,update语句只更新外键字段。 24 * 解决办法: 25 * 让少的一方放弃维护关联关系的权利。 26 * 使用配置的方式实现: 27 * 在一的一方的映射文件中,set标签上使用inverse属性。 28 * inverse:是否放弃维护的权利。 29 * 取值:true 放弃/false 不放弃(默认值) 30 * inverse应该只出现在set标签中。 31 */ 32 @Test 33 public void test1(){ 34 //创建两个实体 35 Customer c = new Customer();//临时态对象 36 c.setCustName("修正b"); 37 c.setCustIndustry("医药制造"); 38 c.setCustSource("网络"); 39 c.setCustLevel("VIP"); 40 c.setCustAddress("昌平区"); 41 c.setCustPhone("010-43853487"); 42 43 LinkMan l = new LinkMan();//临时态 44 l.setLkmName("修正联系人1b"); 45 l.setLkmGender("male"); 46 l.setLkmMobile("13811111111"); 47 l.setLkmPhone("010-34854832"); 48 l.setLkmEmail("332432324@qq.com"); 49 l.setLkmPosition("采购员"); 50 l.setLkmMemo("不好接触"); 51 52 //建立他们之间双向一对多关系 53 l.setCustomer(c); 54 c.getLinkmans().add(l); 55 56 Session s = HibernateUtil.getCurrentSession(); 57 Transaction tx = s.beginTransaction(); 58 //保存 59 s.save(c);//临时态转成持久态,让客户假装不知道有联系人的存在。 60 s.save(l);//临时态转成持久态 61 62 tx.commit(); 63 64 // System.out.println(c.getLinkmans());//还得知道联系人存在 65 // System.out.println(l.getCustomer()); 66 } 67 68 69 /** 70 * 需求: 71 * 创建一个新的联系人 72 * 查询一个id为1的客户 73 * 给id为1的客户分配新创建的联系人对象 74 * 更新客户 75 * 问题: 76 * 在没有放弃维护权利的前提下,会报错。 77 * 更新一个持久态对象,它关联了一个瞬时态对象。 78 * 解决办法: 79 * 配置级联保存更新。 80 * 要操作谁,找谁的配置文件 81 * 要级联操作谁,找谁的配置。 82 * 配置的属性: 83 * cascade 84 * 取值: 85 * save-update 86 */ 87 @Test 88 public void test2(){ 89 //创建联系人对象 90 LinkMan l = new LinkMan();//临时态 91 l.setLkmName("修正联系人1zzz"); 92 l.setLkmGender("male"); 93 l.setLkmMobile("13811111111"); 94 l.setLkmPhone("010-34854832"); 95 l.setLkmEmail("332432324@qq.com"); 96 l.setLkmPosition("采购员"); 97 l.setLkmMemo("不好接触"); 98 99 Session s = HibernateUtil.getCurrentSession(); 100 Transaction tx = s.beginTransaction(); 101 //查询id为1的客户 102 Customer c1 = s.get(Customer.class, 1L);//持久态 103 //建立客户和新创建的联系人之间的双向关联关系 104 c1.getLinkmans().add(l); 105 l.setCustomer(c1); 106 //更新客户 107 s.update(c1);//在放弃维护权利之后,假装不知道有联系人的存在 108 tx.commit(); 109 } 110 111 /** 112 * 删除操作: 113 * 删除联系人:(删除从表数据) 114 * 什么都不用管,直接删 115 * 删除客户:(删除主表数据) 116 * 有从表引用 117 * 数据库中字段允许为null 118 * 把从表中外键字段置为null 119 * 数据库中字段不允许为null 120 * 由于外键字段不为null,所以报错。 121 * 没有从表引用 122 * 直接删除 123 * 124 * 如果配置了主表放弃维护的权利 125 * 配置了级联删除: 126 * 会先删除从表数据,再删除主表数据 127 * 配置方式: 128 * cascade属性 129 * 取值: 130 * delete 131 * 没有配置级联删除: 132 * 不会删除成功,外键约束 133 * 实际开发中: 134 * 级联删除请慎用! 135 * 136 * 137 */ 138 @Test 139 public void test3(){ 140 Session s = HibernateUtil.getCurrentSession(); 141 Transaction tx = s.beginTransaction(); 142 //查询id为2的客户 143 Customer c3 = s.get(Customer.class, 3L);//持久态 144 //删除 145 s.delete(c3);//配置inverse之后,假装不知道联系人的存在 146 tx.commit(); 147 } 148 }
3.Hibernate中的多对多关系映射及操作
前提:
我们学习hibernate中多表映射应该遵循步骤:
1、明确表之前确实是如你所想的关系
2、在数据库中是SQL语句建立他们的之间的关系
3、在实体类中描述出两个实体之间的关系
4、在映射配置文件中建立他们的关系映射
示例:
使用CRM系统中用户和角色表来建立关系


配置文件
SysUser.hbm.xml
1 <!DOCTYPE hibernate-mapping PUBLIC 2 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 4 <hibernate-mapping package="com.gcl.domain.manytomany"> 5 <class name="SysUser" table="sys_user"> 6 <id name="userId" column="user_id"> 7 <generator class="native"></generator> 8 </id> 9 <property name="userCode" column="user_code"></property> 10 <property name="userName" column="user_name"></property> 11 <property name="userPassword" column="user_password"></property> 12 <property name="userState" column="user_state"></property> 13 <!-- 多对多的关系映射 14 涉及的标签: 15 set: 16 作用:用于映射set集合属性的 17 属性: 18 name:指定的是集合属性名称 19 table:指定的是中间表的名称。此时这个属性不能再省略。 20 key: 21 作用:用于指定外键的。 22 属性: 23 column:指定的是当前映射文件所对应的实体在中间的外键字段名称 24 many-to-many: 25 作用:当前映射文件所对应的实体和集合元素之间的关系是多对多 26 属性: 27 class:指定集合元素所对应的实体 28 column:指定的是集合元素所对应的实体在中间表的外键字段名称 29 30 --> 31 <set name="roles" table="user_role_ref"> 32 <key column="user_id"/> 33 <many-to-many class="SysRole" column="role_id"/> 34 </set> 35 </class> 36 </hibernate-mapping> 37 38 39 ------------------------------------------------------------ 40 SysRole.hbm.xml 41 <!DOCTYPE hibernate-mapping PUBLIC 42 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 43 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 44 <hibernate-mapping package="com.gcl.domain.manytomany"> 45 <class name="SysRole" table="sys_role"> 46 <id name="roleId" column="role_id"> 47 <generator class="native"></generator> 48 </id> 49 <property name="roleName" column="role_name"></property> 50 <property name="roleMemo" column="role_memo"></property> 51 <!-- 多对多关系映射 --> 52 <set name="users" table="user_role_ref"> 53 <key column="role_id"/> 54 <many-to-many class="SysUser" column="user_id"/> 55 </set> 56 </class> 57 </hibernate-mapping>
` 双向多对多
1 /** 2 * 双向多对多的保存和删除操作 3 * @author zhy 4 * 5 */ 6 public class HibernateDemo1 { 7 8 /** 9 * 需求: 10 * 创建2个用户 11 * 创建3个角色 12 * 建立用户和角色双向关联关系 13 * 让1号用户包含1号和2号角色 14 * 让2号用户保存2号和3号角色 15 * 保存用户和角色 16 * 问题: 17 * 保存会报错,用户和角色表在保存时都会往中间表中插入数据, 18 * 第二个插入的会造成主键重复 19 * 解决办法; 20 * 让任意一方放弃维护关联关系的权利 21 */ 22 @Test 23 public void test1(){ 24 //创建对象 25 SysUser u1 = new SysUser(); 26 u1.setUserName("aaa"); 27 SysUser u2 = new SysUser(); 28 u2.setUserName("bbb"); 29 30 31 SysRole r1 = new SysRole(); 32 r1.setRoleName("一般操作员"); 33 SysRole r2 = new SysRole(); 34 r2.setRoleName("专业操作员"); 35 SysRole r3 = new SysRole(); 36 r3.setRoleName("系统管理员"); 37 38 //建立关系 39 u1.getRoles().add(r1); 40 u1.getRoles().add(r2); 41 r1.getUsers().add(u1); 42 r2.getUsers().add(u1); 43 44 u2.getRoles().add(r2); 45 u2.getRoles().add(r3); 46 r2.getUsers().add(u2); 47 r3.getUsers().add(u2); 48 49 Session s = HibernateUtil.getCurrentSession(); 50 Transaction tx = s.beginTransaction(); 51 //保存操作 52 s.save(u1); 53 s.save(u2); 54 s.save(r1); 55 s.save(r2); 56 s.save(r3); 57 tx.commit(); 58 } 59 60 61 /** 62 * 在双向多对多关联关系时, 63 * 级联操作:绝对不能配置双向级联删除!!!! 64 */ 65 @Test 66 public void test2(){ 67 Session s = HibernateUtil.getCurrentSession(); 68 Transaction tx = s.beginTransaction(); 69 SysUser u3 = s.get(SysUser.class, 3L); 70 s.delete(u3); 71 tx.commit(); 72 } 73 }

浙公网安备 33010602011771号