[原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )

 

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用

内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系。

本人互联网技术爱好者,互联网技术发烧友

微博:伊直都在0221

QQ:951226918

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1.双向 1-n

 

  1)域模型:从 Order 到 Customer 的多对一双向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性

     

  2)关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键

     

 

   

 

2.单向 n-1 关键点解释

  1)当 Session 从数据库中加载 Java 集合时, 创建的是 Hibernate 内置集合类的实例, 因此在持久化类中定义集合属性时必须把属性声明为 Java 接口类型

      > Hibernate 的内置集合类具有集合代理功能, 支持延迟检索策略

      > 事实上, Hibernate 的内置集合类封装了 JDK 中的集合类, 这使得 Hibernate 能够对缓存中的集合对象进行脏检查, 按照集合对象的状态来同步更新数据库。

 

  2)在定义集合属性时, 通常把它初始化为集合实现类的一个实例. 这样可以提高程序的健壮性, 避免应用程序访问取值为 null 的集合的方法抛出 NullPointerException

 

                                 

  3)Hibernate 使用 <set> 元素来映射 set 类型的属性           

 1  <!-- 在 1 端 -->
 2          <!-- 映射 1对 n 的那个集合属性 -->
 3          <!-- set:映射set类型的属性,
 4               table:set 中的元素中的记录放在哪一个数据表中,该值 需要 n 端的表的名字一致
 5               key:指定n 端 表中的外键列的名字
 6           -->
 7         <set name="orders" table="ORDERS">
 8             <key column="CUSTOMER_ID"></key>
 9             <!-- 指定映射类型  1 - n -->
10             <one-to-many class="Order"/>
11         </set>

 

 

 

 

 

3.代码

 

 

 

 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE hibernate-configuration PUBLIC
 3         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 4         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
 5 <hibernate-configuration>
 6     <session-factory>
 7         <!-- hibernate 连接数据库的基本信息 -->
 8         <property name="connection.username">root</property>
 9         <property name="connection.password">zhangzhen</property>
10         <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
11         <property name="connection.url">jdbc:mysql:///hibernate</property>
12         
13         
14         <!-- 配置hibernate 的节本信息 -->
15         <!-- hibernate 所使用的数据库方言 -->
16         <!--<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>-->
17    <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 
18         <!-- 执行操作时是否在控制台打印SQL  -->
19         <property name="show_sql">true</property>
20         
21         <!-- 是否都SQL 进行格式化 -->
22         <property name="format_sql">true</property>
23         
24         
25         <!-- 指定自动生成数据表的策略 -->
26         <property name="hbm2ddl.auto">update</property>
27         
28         <!-- 设置hibernate 的事务隔离级别 -->
29         <property name="connection.isolation">2</property>
30         
31         
32         <!-- 配置c3p0 -->
33         <property name="hibernate.c3p0.max_size">10</property>
34         <property name="hibernate.c3p0.min_size">5</property>
35         <property name="c3p0.acquire_increment">2</property>
36         <property name="c3p0.idle_test_period">2000</property>
37         <property name="c3p0.timeout">2000</property>
38         <property name="c3p0.max_statements">10</property>
39         
40         
41         <!-- 对于mysql 无效,对于oracle 有效 -->
42         <!-- 设定JDBC 的Statement 读取数据的时候每次从数据库中取出的记录的条数 -->
43         <property name="hibernate.jdbc.fetch_size">100</property>
44         
45         <!-- 设置数据库进行批量删除,批量更新和批量插入的时候的大小 -->
46         <property name="hibernate.jdbc.batch_size">30</property>
47         
48         <!-- 指定关联的 .hbm.xml 文件 -->
49         <!-- 
50             <mapping resource="hibernate/helloworld/News.hbm.xml"/>
51             <mapping resource="hibernate/helloworld/Worker.hbm.xml"/>
52         
53             <mapping resource="com/jason/hibernate/entities/n21/Customer.hbm.xml"/>
54             <mapping resource="com/jason/hibernate/entities/n21/Order.hbm.xml"/>
55         -->
56         
57          <mapping resource="com/jason/hibernate/entities/n21/both/Customer.hbm.xml"/>       
58          <mapping resource="com/jason/hibernate/entities/n21/both/Order.hbm.xml"/>       
59         
60         
61         
62         
63     </session-factory>
64     
65 </hibernate-configuration>
hibernate.cfg.xml

 

 

Customer.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2016-10-5 17:43:02 by Hibernate Tools 3.4.0.CR1 -->
 5 <hibernate-mapping package="com.jason.hibernate.entities.n21.both">
 6 
 7     <class name="Customer" table="CUSTOMERS">
 8     
 9         <id name="customerId" type="java.lang.Integer">
10             <column name="CUSTOMER_ID" />
11             <generator class="native" />
12         </id>
13         
14         <property name="customerName" type="java.lang.String">
15             <column name="CUSTOMER_NAME" />
16         </property>
17         
18         
19         
20          <!-- 在 1 端 -->
21          <!-- 映射 1对 n 的那个集合属性 -->
22          <!-- set:映射set类型的属性,
23               table:set 中的元素中的记录放在哪一个数据表中,该值 需要 n 端的表的名字一致
24               key:指定n 端 表中的外键列的名字
25           -->
26         <set name="orders" table="ORDERS">
27             <key column="CUSTOMER_ID"></key>
28             <!-- 指定映射类型  1 - n -->
29             <one-to-many class="Order"/>
30         </set>
31         
32         
33     </class>
34     
35 </hibernate-mapping>

 

 

Customer

 1 package com.jason.hibernate.entities.n21.both;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class Customer {
 7 
 8     private Integer customerId;
 9     private String customerName;
10 
11     /*
12      * 1.orders 初始化后,防止发生空指针异常
13      * 2.声明集合类型时,需使用接口类型,因为hibernate 在获取集合类型时,返回的是hibernate 内置的集合类型,而不是javaSE 的实现
14      */
15     private Set<Order> orders = new HashSet<>();
16     public Set<Order> getOrders() {
17         return orders;
18     }
19 
20     public void setOrders(Set<Order> orders) {
21         this.orders = orders;
22     }
23 
24     public Integer getCustomerId() {
25         return customerId;
26     }
27 
28     public void setCustomerId(Integer customerId) {
29         this.customerId = customerId;
30     }
31 
32     public String getCustomerName() {
33         return customerName;
34     }
35 
36     public void setCustomerName(String customerName) {
37         this.customerName = customerName;
38     }
39 
40     @Override
41     public String toString() {
42         return "Customer [customerId=" + customerId + ", customerName="
43                 + customerName + "]";
44     }
45 
46     
47 }

 

 

Order.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2016-10-5 17:43:02 by Hibernate Tools 3.4.0.CR1 -->
 5 <hibernate-mapping package="com.jason.hibernate.entities.n21.both">
 6     <class name="Order" table="ORDERS">
 7     
 8         <id name="orderId" type="java.lang.Integer">
 9             <column name="ORDER_ID" />
10             <generator class="native" />
11         </id>
12         
13         <property name="orderName" type="java.lang.String">
14             <column name="ORDER_NAME" />
15         </property>
16         
17         <!-- 映射 多对一 关联关系 -->
18         <!-- 
19             name: 'n'端 关联 '1'端的属性的名字
20             class: '1'端 属性对应的类名
21             colum: '1'端  在 'n'端 对应的数据表中的外键的名字
22          -->
23         <many-to-one name="customer" class="Customer">
24             <column name="CUSTOMER_ID" />
25         </many-to-one>
26         
27        
28         
29     </class>
30     
31 </hibernate-mapping>

 

 

Order

 1 package com.jason.hibernate.entities.n21.both;
 2 
 3 public class Order {
 4 
 5     private Integer orderId;
 6     private String orderName;
 7 
 8     private Customer customer;
 9 
10     public Integer getOrderId() {
11         return orderId;
12     }
13 
14     public void setOrderId(Integer orderId) {
15         this.orderId = orderId;
16     }
17 
18     public String getOrderName() {
19         return orderName;
20     }
21 
22     public void setOrderName(String orderName) {
23         this.orderName = orderName;
24     }
25 
26     public Customer getCustomer() {
27         return customer;
28     }
29     
30     public void setCustomer(Customer customer) {
31         this.customer = customer;
32     }
33 
34     @Override
35     public String toString() {
36         return "Order [orderId=" + orderId + ", orderName=" + orderName
37                 + ", customer=" + customer + "]";
38     }
39 
40     
41 }

 

 

 

HibernateTest.java

  1 package com.jason.hibernate.entities.n21.both;
  2 
  3 import hibernate.helloworld.News;
  4 import hibernate.helloworld.Pay;
  5 import hibernate.helloworld.Worker;
  6 
  7 import java.io.FileInputStream;
  8 import java.io.FileNotFoundException;
  9 import java.io.InputStream;
 10 import java.sql.Blob;
 11 import java.sql.Connection;
 12 import java.sql.Date;
 13 import java.sql.SQLException;
 14 
 15 import org.hibernate.Hibernate;
 16 import org.hibernate.LazyInitializationException;
 17 import org.hibernate.Session;
 18 import org.hibernate.SessionFactory;
 19 import org.hibernate.Transaction;
 20 import org.hibernate.cfg.Configuration;
 21 import org.hibernate.jdbc.Work;
 22 import org.hibernate.service.ServiceRegistry;
 23 import org.hibernate.service.ServiceRegistryBuilder;
 24 import org.junit.After;
 25 import org.junit.Before;
 26 import org.junit.Test;
 27 import org.omg.CORBA.ORB;
 28 
 29 public class HibernateTest {
 30 
 31     private SessionFactory sessionFactory;
 32     private Session session;
 33     private Transaction transaction;
 34 
 35     @Test
 36     public void test() {
 37 
 38         // 1. 创建一个SessionFatory 对象
 39         SessionFactory sessionFactory = null;
 40 
 41         // 1) 创建Configuration 对象:对应hibernate 的基本配置信息 和 对象关系映射信息
 42         Configuration configuration = new Configuration().configure();
 43 
 44         // 2) 创建一个ServiceRegistry 对象:hibernate 4.x 新天添加的对象。
 45         // hibernate 的任何配置 和 服务都需要在该对象中注册后才有效
 46         ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
 47                 .applySettings(configuration.getProperties())
 48                 .buildServiceRegistry();
 49 
 50         // sessionFactory = configuration.buildSessionFactory();
 51         sessionFactory = configuration.buildSessionFactory(serviceRegistry);
 52 
 53         // 2. 创建一个session 对象
 54         Session session = sessionFactory.openSession();
 55 
 56         // 3. 开启事物
 57         Transaction transaction = session.beginTransaction();
 58 
 59         // 4.执行保存操作
 60         News news = new News("java", "jason", new Date(
 61                 new java.util.Date().getTime()));
 62         session.save(news);
 63 
 64         // 5.提交事物
 65         transaction.commit();
 66         // 6.关闭session
 67         session.close();
 68         // 7.关闭SessionFactory 对象
 69         sessionFactory.close();
 70     }
 71 
 72     // 创建上述三个对象
 73     @Before
 74     public void init() {
 75         Configuration configuration = new Configuration().configure();
 76         ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
 77                 .applySettings(configuration.getProperties())
 78                 .buildServiceRegistry();
 79 
 80         sessionFactory = configuration.buildSessionFactory(serviceRegistry);
 81 
 82         session = sessionFactory.openSession();
 83 
 84         transaction = session.beginTransaction();
 85     }
 86 
 87     // 关闭上述三个对象
 88     @After
 89     public void destroy() {
 90         transaction.commit();
 91         session.close();
 92         sessionFactory.close();
 93     }
 94 
 95     @Test
 96     public void testDelete() {
 97         // 在不设定级联关系的情况下,且 1 端的对象 有 n端的对象在引用,不能直接删除1 端的对象
 98         Customer customer = (Customer) session.get(Customer.class, 1);
 99         session.delete(customer);
100     }
101 
102     
103     @Test
104     public void testUpdate2(){
105         Customer customer = (Customer) session.get(Customer.class, 1);
106         customer.getOrders().iterator().next().setOrderName("BBBB");
107     }
108     @Test
109     public void testUpdate() {
110         Order order = (Order) session.get(Order.class, 1);
111         order.getCustomer().setCustomerName("tom2");
112 
113     }
114 
115     @Test
116     public void testOne2ManyGet() {
117         
118         //1.对n 的一端的集合使用延迟加载
119         Customer customer = (Customer) session.get(Customer.class, 1);
120         System.out.println(customer.getCustomerName());
121         
122         //2.返回n端的集合是hibernate 的内置集合类型。该类型具有延迟加载和存放代理对象的功能
123         System.out.println(customer.getOrders().getClass());
124         
125         //3.可能抛出     LazyInitializationException 异常
126         
127         //4.再需要使用集合中元素的时候进行初始化
128     
129         
130         
131     }
132     
133     
134     @Test
135     public void testManyToOneGet() {
136         // 1.若查询n 的一端的对象,则默认情况下,只查询了n 的一端的对象,而没有查询关联的1 端的对象
137         // 延迟加载
138         Order order = (Order) session.get(Order.class, 1);
139         System.out.println(order);
140 
141         // 2.在需要使用到关联的对象,才发送对应的sql 语句
142         Customer customer = order.getCustomer();
143         System.out.println(customer);
144 
145         // 3.获取order对象,默认情况,其关联的Customer 对象是一个代理对象
146     }
147 
148     @Test
149     public void testManyToOneSave() {
150         Customer customer = new Customer();
151         customer.setCustomerName("AA");
152 
153         Order order1 = new Order();
154         order1.setOrderName("order-1");
155 
156         Order order2 = new Order();
157         order2.setOrderName("order-2");
158 
159         // 设定关联关系
160         order1.setCustomer(customer);
161         order2.setCustomer(customer);
162 
163         customer.getOrders().add(order1);
164         customer.getOrders().add(order2);
165 
166         // 执行svae操作:先插入 Customer,再插入Order,3条insert,2条update
167         // 因为1端 和 n端 都维护关联关系,所以多出四条
168         // 可以在1 端的set节点,指定inverse=true ,来使1端放弃维护关联关系
169         // 建议先插入1 的一端,后插入 n端
170         //
171         session.save(customer);
172         session.save(order1);
173         session.save(order2);
174 
175         // 先插入Order,再插入Customer,3条insert,4条update
176         // session.save(order1);
177         // session.save(order2);
178         //
179         // session.save(customer);
180 
181     }
182 
183 }

 

 

 

 

 

关于set标签

  1) <set> 元素来映射持久化类的 set 类型的属性 name: 设定待映射的持久化类的属性的

  2)<key> 元素设定与所关联的持久化类对应的表的外键 column: 指定关联表的外键名

  3)<one-to-many> 元素设定集合属性中所关联的持久化类 class: 指定关联的持久化类的类名

  4)inverse 属性

    ① 在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系. inverse = false 的为主动方,inverse = true 的为被动方, 由主动方负责维护关联关系

        ② 在没有设置 inverse=true 的情况下,父子两边都维护父子 关系

    ③ 在 1-n 关系中,将 n 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)

    ④ 在 1-N 关系中,若将 1 方设为主控方

      >会额外多出 update 语句。

      >插入数据时无法同时插入外键列,因而无法为外键列添加非空约束

 

  5)cascade 属性(了解)

    ① 在对象 – 关系映射文件中, 用于映射持久化类之间关联关系的元素, <set>, <many-to-one> 和 <one-to-one> 都有一个 cascade 属性, 它用于指定如何操纵与当前对象关联的其他对象.

 

             

 

  6)order-by 属性  

    ①  <set> 元素有一个 order-by 属性, 如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序。设置的是表的字段名,而不是持久化类的属性名

    ②  order-by 属性中还可以加入 SQL 函数

  

 

 

说明:
  1.在 n 端的 .hbm.xml 中映射关联关系
1 <!-- 映射 多对一 关联关系 -->
2         <!-- 
3             name: 'n'端 关联 '1'端的属性的名字
4             class: '1'端 属性对应的类名
5             colum: '1'端  在 'n'端 对应的数据表中的外键的名字
6          -->
7         <many-to-one name="customer" class="Customer">
8             <column name="CUSTOMER_ID" />
9         </many-to-one>

 









  
posted @ 2016-10-05 22:17  jason_zhangz  阅读(521)  评论(0编辑  收藏  举报