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 }

 

posted @ 2017-06-01 19:05  细节造就完美  阅读(54)  评论(0)    收藏  举报