zoukankan      html  css  js  c++  java
  • hibernate关联关系映射

    Hibernate关联映射分类

    •  单向关系:只需单向访问关联端。例如:只能通过老师访问学生或只能通过学生访问老师。
    • 双向关系:关联的两端可以访问。如老师和学生可以互相访问。

    单向关联分为:

    • 单向N-1
    • 单向1-N
    • 单向1-1
    • 单向N-N

    双向关联分为:

    •  双向1-1
    •  双向1-N
    •  双向N-N 

    1  单向多对一:N-1

    案例:一个客户有多个订单,从订单一方访问客户信息

    1.1  Order对象和映射文件

    //对象文件
    public class Order {
        private int id;
        private String orderNumber;
        private Customer customer; 
    //以下所有的对象都省略了get/set方法 }
    <hibernate-mapping>
        <class name="com.silvan.pojo.Order" table="t_order">
            <id name="id" type="java.lang.Integer">
                <generator class="native"></generator>
            </id>
            <property name="orderNumber" />
    <!-- name属性名;column外键列名;class该属性关联的全类名-->
            <many-to-one name="customer" column="cust_id" class="com.silvan.pojo.Customer" not-null="true"/>
        </class>
    </hibernate-mapping>

    1.2 Customer对象和映射文件

    public class Customer {
        private int id;
        private String custName;    
    }
    <hibernate-mapping>
        <class name="com.silvan.pojo.Customer" table="t_customer">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="custName" />
        </class>
    </hibernate-mapping>

    1.3  hibernate.cfg.xml加上映射文件:

    <mapping resource="com/silvan/pojo/Order.hbm.xml" />

    <mapping resource="com/silvan/pojo/Customer.hbm.xml" />

    1.4 测试方法

    //保存订单和客户信息,先保存客户信息
    public void save(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Customer customer = new Customer();
                customer.setCustName("qinqin");
                Order order = new Order();
                order.setOrderNumber("1");
                order.setCustomer(customer);
                session.save(customer);
                session.save(order); 
                tx.commit();
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }
    //打印的保存过程:
    //Hibernate: select hibernate_sequence.nextval from dual
    //Hibernate: select hibernate_sequence.nextval from dual
    //Hibernate: insert into t_customer (custName, id) values (?, ?)
    //Hibernate: insert into t_order (orderNumber, cust_id, id) values (?, ?, ?)
    //查询订单信息,通过订单信息查询客户信息,这时候会发出一条查询客户信息的SQL语句
        public void query(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Order order = (Order) session.get(Order.class, 4);
            System.out.println(order.getCustomer().getCustName());
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }

    1.5  级联(cascade

    当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,而是会抛出TransientObjectException.如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。 级联指的是当主控方执行操作时,关联对象(被动方)是否同步执行同一操作。

    所以如果上面案例中设置成

    <many-to-one name="customer" cascade="save-update" column="cust_id" class="com.silvan.pojo.Customer" not-null="true"/>则保存的时候不需要session.save(customer);也可以保存客户信息;而如果没有设置cascade,不保存客户信息的情况下去保存订单信息的话会抛出异常。

    2 单向一对多:1 - N

    案例:一个客户有多个订单,从客户一方访问订单信息

    2.1 Order对象和映射文件

    //对象文件
    public class Order {
        private int id;
        private String orderNumber;
    }
    <hibernate-mapping>
        <class name="com.silvan.pojo.Order" table="t_order">
            <id name="id" type="java.lang.Integer">
                <generator class="native"></generator>
            </id>
            <property name="orderNumber" />
        </class>
    </hibernate-mapping>

    2.2 Customer对象和映射文件

    public class Customer {
        private int id;
    private String custName;  
    private Set orders=new HashSet();  
    }
    <hibernate-mapping>
        <class name="com.silvan.pojo.Customer" table="t_customer">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="custName" />
    <!-- name属性名;column外键列名;class该属性关联的全类名; cascade 级联方式 -->
            <set name="orders" cascade="save-update">
                  <key column="cust_id"></key>
                  <one-to-many class="com.silvan.pojo.Order" />
            </set>
        </class>
    </hibernate-mapping>

    2.3 测试方法

    //保存订单和客户信息,
    //先保存客户和订单的基本信息,然后更新订单中的外键客户编号信息
    public void save(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Customer customer = new Customer();
                customer.setCustName("qinqin");
                
                Order order1 = new Order();
                order1.setOrderNumber("1order");
                Order order2 = new Order();
                order2.setOrderNumber("2order");
                
                Set<Order> orders = new HashSet();
                orders.add(order1);
                orders.add(order2);
                customer.setOrders(orders);
                session.save(customer);
                tx.commit();
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }
    //打印的保存过程:
    //Hibernate: select hibernate_sequence.nextval from dual
    //Hibernate: select hibernate_sequence.nextval from dual
    //Hibernate: select hibernate_sequence.nextval from dual
    //Hibernate: insert into t_customer (custName, id) values (?, ?)
    //Hibernate: insert into t_order (orderNumber, id) values (?, ?)
    //Hibernate: insert into t_order (orderNumber, id) values (?, ?)
    //Hibernate: update t_order set cust_id=? where id=?
    //Hibernate: update t_order set cust_id=? where id=?
        public void query(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Customer customer = (Customer) session.get(Customer.class,1);
                Set orders = customer.getOrders();
                for(Object obj:orders){
                    Order order = (Order) obj;
                    System.out.println(order.getOrderNumber());
                }
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }

    3 双向N-1

    双向 1-N 与 双向 N-1 是完全相同的两种情形

    双向 1-N 需要在 1 的一端可以访问 N 的一端, 反之依然

    案例:一个客户有多个订单,从客户一方访问订单信息,从订单一方访问客户信息

    3.1 Order

    注意:测试中保存先保存哪一方,cascade就应该设置在哪一方的映射文件中

    //对象文件
    public class Order {
        private int id;
        private String orderNumber;
        private Customer customer;}
    <hibernate-mapping>
        <class name="com.silvan.pojo.Order" table="t_order">
            <id name="id" type="java.lang.Integer">
                <generator class="native"></generator>
            </id>
            <property name="orderNumber" />
            <many-to-one name="customer" column="cust_id" class="com.silvan.pojo.Customer" not-null="true"/>
        </class>
    </hibernate-mapping>

    3.2Customer

    public class Customer {
        private int id;
    private String custName;  
    private Set orders=new HashSet();  
    }
    <hibernate-mapping>
        <class name="com.silvan.pojo.Customer" table="t_customer">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="custName" />
    <!-- name属性名;column外键列名;class该属性关联的全类名 -->
            <set name="orders" cascade="save-update" >
                  <key column="cust_id"></key>
                  <one-to-many class="com.silvan.pojo.Order" />
            </set>
        </class>
    </hibernate-mapping>

    3.3 测试方法

    //保存订单和客户信息,
    public void save(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Customer customer = new Customer();
                customer.setCustName("qinqin");
                
                Order order1 = new Order();
                order1.setOrderNumber("1order");
                order1.setCustomer(customer);
                Order order2 = new Order();
                order2.setOrderNumber("2order");
                order2.setCustomer(customer);
                
                Set<Order> orders = new HashSet();
                orders.add(order1);
                orders.add(order2);
                customer.setOrders(orders);
                session.save(customer);
                tx.commit();
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }
        
        public void query(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                //从1的一端获取多的一端信息
                Customer customer = (Customer) session.get(Customer.class,1);
                Set orders = customer.getOrders();
                for(Object obj:orders){
                    Order order = (Order) obj;
                    System.out.println(order.getOrderNumber());
                }
                //从多的一端获取1的一端信息
                Order order = (Order) session.get(Order.class, 2);
                System.out.println(order.getCustomer().getCustName());
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }

    3.4 inverse属性(inverse:相反的,逆向的)

    原理:

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

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

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

    l  在 1-N 关系中,若将 1 方设为主控方 会额外多出 update 语句。

     

    案例结果:1-N双向映射情况下插入数据语句

    //用户映射文件中设置inverse="false":
    Hibernate: select hibernate_sequence.nextval from dual
    Hibernate: select hibernate_sequence.nextval from dual
    Hibernate: select hibernate_sequence.nextval from dual
    Hibernate: insert into t_customer (custName, id) values (?, ?)
    Hibernate: insert into t_order (orderNumber, cust_id, id) values (?, ?, ?)
    Hibernate: insert into t_order (orderNumber, cust_id, id) values (?, ?, ?)
    Hibernate: update t_order set cust_id=? where id=?
    Hibernate: update t_order set cust_id=? where id=?
    
    //用户映射文件中设置inverse="true":
    Hibernate: select hibernate_sequence.nextval from dual
    Hibernate: select hibernate_sequence.nextval from dual
    Hibernate: select hibernate_sequence.nextval from dual
    Hibernate: insert into t_customer (custName, id) values (?, ?)
    Hibernate: insert into t_order (orderNumber, cust_id, id) values (?, ?, ?)
    Hibernate: insert into t_order (orderNumber, cust_id, id) values (?, ?, ?)

    4 单向1-1关联

    4.1 外键关联:

    l  单向 1-1,POJO 与 N-1 没有丝毫区别。

    l  基于外键的单向 1-1 映射文件:只需要在原有的 many-to-one 元素添加 unique=“true”,用以表示 N 的一端必须唯一即可,N的一端增加了唯一约束, 即成为单向 1-1.

    案例:假设一个订单只有一个客户,一个客户只有一个订单。

    4.1.1 Order

    <hibernate-mapping>
        <class name="com.silvan.pojo.Order" table="t_order">
            <id name="id" type="java.lang.Integer">
                <generator class="native"></generator>
            </id>
            <property name="orderNumber" />
            <many-to-one name="customer" unique="true" cascade="save-update" column="cust_id" class="com.silvan.pojo.Customer" not-null="true"/>
        </class>
    </hibernate-mapping>

    4.1.2 Customer

    <hibernate-mapping>
        <class name="com.silvan.pojo.Customer" table="t_customer">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="custName" />
        </class>
    </hibernate-mapping>

    4.1.3 测试方法

    //保存订单和客户信息,
    public void save(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Customer customer = new Customer();
                customer.setCustName("qinqin");
                
                Order order1 = new Order();
                order1.setOrderNumber("1order");
                order1.setCustomer(customer);
                
                session.save(order1);
                tx.commit();
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }

    4.2 主键关联:

    一对一的另一种解决方式就是主键关联,在这种关联关系中,要求两个对象的主键必须保持一致,通过两个表的主键建立关联关系须外键参与。

    4.2.1 order

    //对象文件
    public class Order {
        private int id;
        private String orderNumber;
        private Customer customer;}
    <hibernate-mapping>
        <class name="com.silvan.pojo.Order" table="t_order">
            <id name="id" type="java.lang.Integer">
                <generator class="foreign">
                    <param name="property">customer</param>
                </generator>
            </id>
            <property name="orderNumber" />
            <one-to-one name="customer" cascade="save-update" class="com.silvan.pojo.Customer" constrained="true"/>
        </class>
    </hibernate-mapping>

    4.2.2Customer

    public class Customer {
        private int id;
    private String custName;  
    }
    <hibernate-mapping>
        <class name="com.silvan.pojo.Customer" table="t_customer">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="custName" />
        </class>
    </hibernate-mapping>

    4.2.3 测试方法

    //保存订单和客户信息,
    public void save(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Customer customer = new Customer();
                customer.setCustName("qinqin");
                
                Order order1 = new Order();
                order1.setOrderNumber("1order");
                order1.setCustomer(customer);
                
                session.save(order1);
                tx.commit();
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }
        //根据订单信息查询出客户名称
        public void query(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Order order = (Order) session.get(Order.class,1);
                System.out.println(order.getCustomer().getCustName());
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }

    5 双向1-1关联

    5.1 外键关联

    5.1.1 Order

    //对象文件
    public class Order {
        private int id;
        private String orderNumber;
        private Customer customer;}
    <hibernate-mapping>
        <class name="com.silvan.pojo.Order" table="t_order">
            <id name="id" type="java.lang.Integer">
                <generator class="native"/>
            </id>
            <property name="orderNumber" />
            <many-to-one name="customer" unique="true" cascade="save-update" column="cust_id" class="com.silvan.pojo.Customer" not-null="true"/>
        </class>
    </hibernate-mapping>

    5.1.2 Customer

    public class Customer {
        private int id;
        private String custName;
    private Order order; 
    }
    <hibernate-mapping>
        <class name="com.silvan.pojo.Customer" table="t_customer">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="custName" />
    <!-- 外键方式:一对一关联。该元素使用 property-ref属性指定使用被关联实体主键以外的字段作为关联字段-->
            <one-to-one name="order" class="com.silvan.pojo.Order" property-ref="customer"></one-to-one>
        </class>
    </hibernate-mapping>

    5.1.3 测试方法

    //保存订单和客户信息,
    public void save(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Customer customer = new Customer();
                customer.setCustName("qinqin");
                
                Order order1 = new Order();
                order1.setOrderNumber("1order");
                order1.setCustomer(customer);
                
                session.save(order1);
                tx.commit();
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }
        @Test
        public void query(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Order order = (Order) session.get(Order.class,1);
            System.out.println(order.getCustomer().getCustName());
                
        Customer customer = (Customer) session.get(Customer.class,2);
        System.out.println(customer.getOrder().getOrderNumber());
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }

    5.2 主键关联

    5.2.1 order

    //对象文件
    public class Order {
        private int id;
        private String orderNumber;
        private Customer customer;}
    <hibernate-mapping>
        <class name="com.silvan.pojo.Order" table="t_order">
            <id name="id" type="java.lang.Integer">
                <generator class="foreign">
                    <param name="property">customer</param>
                </generator>
            </id>
            <property name="orderNumber" />
            <one-to-one name="customer" cascade="save-update" class="com.silvan.pojo.Customer" constrained="true"/>
        </class>
    </hibernate-mapping>

    5.2.2 Customer

    public class Customer {
        private int id;
        private String custName;
        private Order order;}
    <hibernate-mapping>
        <class name="com.silvan.pojo.Customer" table="t_customer">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="custName" />
            <one-to-one name="order" class="com.silvan.pojo.Order" ></one-to-one>
        </class>
    </hibernate-mapping>

    5.2.3 测试方法

    //保存订单和客户信息,
    public void save(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Customer customer = new Customer();
                customer.setCustName("qinqin");
                
                Order order1 = new Order();
                order1.setOrderNumber("1order");
                order1.setCustomer(customer);
                
                session.save(order1);
                tx.commit();
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }
        @Test
        public void query(){
            Session session = HibernateUtil.getSession();
            Transaction tx = null;
            try{
                tx = session.beginTransaction();
                Order order = (Order) session.get(Order.class,1);
            System.out.println(order.getCustomer().getCustName());    
            Customer customer = (Customer) session.get(Customer.class,1);        System.out.println(customer.getOrder().getOrderNumber());
            }catch(Exception e){
                if(tx!=null){
                    tx.rollback();
                }
                e.printStackTrace();
            }finally{
                HibernateUtil.closeSession(session);
            }
        }
  • 相关阅读:
    网络流(平面图转对偶图)
    666
    期望总结
    docker-1-简介
    22、整合mybatis
    21、整合Druid数据源
    20、Springboot 与数据访问(JDBC/自动配置)
    19、配置嵌入式servlet容器(下)
    18、配置嵌入式servlet容器(2)
    17、配置嵌入式servlet容器(1)
  • 原文地址:https://www.cnblogs.com/zhouyeqin/p/7196049.html
Copyright © 2011-2022 走看看