hibernate关联关系映射

Posted zhouyeqin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
        }
    }

 


以上是关于hibernate关联关系映射的主要内容,如果未能解决你的问题,请参考以下文章

关联映射级联操作关系维护 ---- Hibernate之一对多|多对一关系

Hibernate—— 联合主键 一对一关联关系映射(xml和注解) 和 领域驱动设计

Hibernate关联关系映射

Hibernate关联映射关系

Hibernate框架学习之注解配置关系映射

Hibernate关联映射