zoukankan      html  css  js  c++  java
  • [原创]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>








      
  • 相关阅读:
    机器学习
    区块链
    MongoDB 生态 – 可视化管理工具
    分库分表适用场景
    权限管理
    ASP .NET Core 2.1 HTTP Error 502.5 – Process Failure
    Core2.0 项目到2.1
    Anaconda 安装和使用Numpy、Scipy、pandas、Scikit-learn
    NET Core 2.1.0 now available
    SQL Server发布订阅功能研究
  • 原文地址:https://www.cnblogs.com/jasonHome/p/5932744.html
Copyright © 2011-2022 走看看