通知
此博客运行在jpress系统上,如果你喜欢此博客模板,请加QQ群:1061691290(whimurmur模板/jpress插件),免费下载使用

HIBERNATE知识复习记录3-关联关系

3585人浏览 / 0人评论 | 作者:whisper  | 分类: hibernate  | 标签: 框架  /  hibernate  | 

作者:whisper

链接:http://proprogrammar.com:443/article/294

声明:请尊重原作者的劳动,如需转载请注明出处


       先上一张图,关于几种关系映射:

  

  抄一段解释:

  基本映射是对一个实体进行映射,关联映射就是处理多个实体之间的关系,将关联关系映射到数据库中,所谓的关联关系在对象模型中有一个或多个引用。关联关系分为上述七种,但是由于相互之间有各种关系,可以简化,例如:多对一与一对多映射,只是侧重的角度不对而已。

  Hibernate将关系映射分为以上四种,现在来看关系映射其实就两种,甚至一种。

  1、从对象的加载方向上分为单向和双向两种。

        单向和双向只影响数据的加载,并不影响数据的存储。不论是一对一,一对多还是多对多,单向和双向生成的数据库表是一样,单向和双向的不同是由对象模型决定的。

  2、从对象的映射关系上分为一对多和多对一两种,它们又是从不同角度说的,所以也可以说是一种。

        一对一关联映射是多对一关联映射的特例,只是在“多”的一端加上唯一的限制之后,用来表示一对一的关联关系。

        多对多关联映射是一对多关联映射的特例,它们呢都是使用集合来表示多的关系,用<key>标签定义当前表的主键。

  以上是从SSH:Hibernate框架(七种关联关系映射及配置详解)摘抄下来的,具体内容可以看这篇文章。

  好了,下面复习一下我以前的学习内容吧。

  先说一说一对一关系。

  1-1,外键关联:

  部门与部门经理,一个部门对应一个部门经理。

  Department类

package onetoone.primary;

public class Department {
    private Integer deptId;
    private String deptName;
    private Manager mgr;
    public Integer getDeptId() {
        return deptId;
    }
    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }
    public String getDeptName() {
        return deptName;
    }
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
    public Manager getMgr() {
        return mgr;
    }
    public void setMgr(Manager mgr) {
        this.mgr = mgr;
    }
}

  Manager类

package onetoone.primary;

public class Manager {
    private Integer mgrId;
    private String mgrName;
    private Department dept;
    public Integer getMgrId() {
        return mgrId;
    }
    public void setMgrId(Integer mgrId) {
        this.mgrId = mgrId;
    }
    public String getMgrName() {
        return mgrName;
    }
    public void setMgrName(String mgrName) {
        this.mgrName = mgrName;
    }
    public Department getDept() {
        return dept;
    }
    public void setDept(Department dept) {
        this.dept = dept;
    }
}

  Department.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-23 9:47:29 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="onetoone.foreign">
    <class name="Department" table="DEPARTMENT">
        <id name="deptId" type="java.lang.Integer">
            <column name="DEPT_ID" />
            <generator class="native" />
        </id>
        <property name="deptName" type="java.lang.String">
            <column name="DEPT_NAME" />
        </property>
        
        <!-- 使用many-to-one 的方式来映射1-1关联关系 -->
        <many-to-one name="mgr" class="Manager" column="MGR_ID" unique="true"></many-to-one>
    </class>
</hibernate-mapping>

  Manager.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-23 9:47:29 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="onetoone.foreign">
    <class name="Manager" table="MANAGER">
        <id name="mgrId" type="java.lang.Integer">
            <column name="MGR_ID" />
            <generator class="native" />
        </id>
        <property name="mgrName" type="java.lang.String">
            <column name="MGR_NAME" />
        </property>
        
        <!-- 映射1-1的关联关系:在对应的数据表中已经有外键了,当前持久化为使用one-to-one进行映射 
            没有外键的一端需要使用one-to-one元素,该元素使用property-ref属性指定使用被关联实体主键以外的字段作为关联字段
         -->
        <one-to-one name="dept" class="Department" property-ref="mgr"></one-to-one>
  
    </class>
    
</hibernate-mapping>

  这里是双向的外键关联,生成的部门表中会有一个经理表的外键,双向还是单向对数据模型并没有影响,影响的是对象模型。单向的外键关联可以看我上面提供的链接。

  HibernateTest类

package onetoone.primary;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {
    private SessionFactory sessionFactory;
    
    private Session session;
    
    private Transaction transaction;
    
    @Before
    public void init()
    {
        System.out.println("init");

        // 1. 创建一个SessionFactory对象
        sessionFactory = null;
        Configuration configuration = new Configuration().configure();
        
        // before 4.0
//        sessionFactory = configuration.buildSessionFactory();
        
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
                                                                      .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        // 2. 创建一个Session 对象
        session = sessionFactory.openSession();
        
        // 3. 开启事务
        transaction = session.beginTransaction();
        
    }
    
    @After
    public void destory()
    {
        System.out.println("destory");
        // 5. 提交事务
        transaction.commit();
        
        // 6. 关闭Session
        session.close();
        
        // 7. 关闭SesssionFactory
        sessionFactory.close();
    }
    
    @Test
    public void testSave()
    {
        Department department = new Department();
        department.setDeptName("DEPT-BB");
        
        Manager manager = new Manager();
        manager.setMgrName("MGR-BB");
        
        department.setMgr(manager);
        manager.setDept(department);
        
        // 建议先保存没有外键列的那个对象,这样会减少UPDATE语句
        session.save(manager);
        session.save(department);
    }
    
    @Test
    public void testGet()
    {
        //1. 默认情况下对关联属性使用懒加载,可能会出现懒加载异常
        Department dept = (Department) session.get(Department.class, 1);
        System.out.println(dept.getDeptName());
        
        //3. 查询Manager对象的连接条件应该是dept.manager_id=mgr.manager_id
        // 而不应该是dept.dept_id = mgr.manager_id
        Manager mgr = dept.getMgr();
        System.out.println(mgr.getMgrName());
        
    }
    
    @Test
    public void testGet2()
    {
        // 在查询没有外键的实体对象时,使用的左外连接查询,一并查询出关联的对象,并已经进行初始化
        Manager mgr = (Manager)session.get(Manager.class, 1);
        System.out.println(mgr.getMgrName());
    }
}

  1-1,主键关联:

  Department类:

package onetoone.primarykey;

public class Department {
    private Integer deptId;
    private String deptName;
    private Manager mgr;
    public Integer getDeptId() {
        return deptId;
    }
    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }
    public String getDeptName() {
        return deptName;
    }
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
    public Manager getMgr() {
        return mgr;
    }
    public void setMgr(Manager mgr) {
        this.mgr = mgr;
    }
}

  Manager类:

package onetoone.primarykey;

public class Manager {
    private Integer mgrId;
    private String mgrName;
    private Department dept;
    public Integer getMgrId() {
        return mgrId;
    }
    public void setMgrId(Integer mgrId) {
        this.mgrId = mgrId;
    }
    public String getMgrName() {
        return mgrName;
    }
    public void setMgrName(String mgrName) {
        this.mgrName = mgrName;
    }
    public Department getDept() {
        return dept;
    }
    public void setDept(Department dept) {
        this.dept = dept;
    }
}

  Department.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                                   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-23 9:47:29 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="onetoone.primary">
 <class name="Department" table="DEPARTMENT">
  <id name="deptId" type="java.lang.Integer">
  <!-- 使用外键的方式来生成当前的主键  -->
   <generator class="foreign">
          <!-- property 属性指这使用当前持久化类的哪一个属性的主键作为外键  -->
       <param name="property">mgr</param>
   </generator>
  </id>
  <property generated="never" lazy="false" name="deptName" type="java.lang.String">
   <column name="DEPT_NAME"/>
  </property>
  <!-- 采用主键生成策略的一端增加one-to-one元素映射关联属性,
      其 one-to-one 属性还应增加constrained="true"属性,以使当前主键增加外键约束
    constrained="true"在新增或删除记录时会同时操作关联表
   -->
  <one-to-one class="Manager" name="mgr" constrained="true"/>
 </class>
</hibernate-mapping>

  Manager.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                                   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-23 9:47:29 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="onetoone.primary">
 <class name="Manager" table="MANAGER">
  <id name="mgrId" type="java.lang.Integer">
   <column name="MGR_ID"/>
   <generator class="native"/>
  </id>
  <property generated="never" lazy="false" name="mgrName" type="java.lang.String">
   <column name="MGR_NAME"/>
  </property>
  <!-- 怎么加载对象,抓取策略:join联合查询(默认),select:一条条的查询 -->
  <one-to-one class="Department" name="dept" fetch="join" />
 </class>
</hibernate-mapping>

  这里采用的是双向一对一主键生成策略,单向的一对一主键生成策略可以查看上面提供的文章。

  HibernateTest类

package onetoone.primarykey;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {
    private SessionFactory sessionFactory;
    
    private Session session;
    
    private Transaction transaction;
    
    @Before
    public void init()
    {
        System.out.println("init");

        // 1. 创建一个SessionFactory对象
        sessionFactory = null;
        Configuration configuration = new Configuration().configure();
        
        // before 4.0
//        sessionFactory = configuration.buildSessionFactory();
        
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
                                                                      .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        // 2. 创建一个Session 对象
        session = sessionFactory.openSession();
        
        // 3. 开启事务
        transaction = session.beginTransaction();
        
    }
    
    @After
    public void destory()
    {
        System.out.println("destory");
        // 5. 提交事务
        transaction.commit();
        
        // 6. 关闭Session
        session.close();
        
        // 7. 关闭SesssionFactory
        sessionFactory.close();
    }
    
    @Test
    public void testSave()
    {
        Department department = new Department();
        department.setDeptName("DEPT-BB");
        
        Manager manager = new Manager();
        manager.setMgrName("MGR-BB");
        
        department.setMgr(manager);
        manager.setDept(department);
        
        // 先插入哪一个都不会有多余的update
        session.save(department);
        session.save(manager);
    }
    
    @Test
    public void testGet()
    {
        //1. 默认情况下对关联属性使用懒加载,可以会出现懒加载异常
        Department dept = (Department) session.get(Department.class, 1);
        System.out.println(dept.getDeptName());
        
        //3. 查询Manager对象的连接条件应该是dept.manager_id=mgr.manager_id
        // 而不应该是dept.dept_id = mgr.manager_id
        Manager mgr = dept.getMgr();
        System.out.println(mgr.getMgrName());
        
    }
    
    @Test
    public void testGet2()
    {
        // 在查询没有外键的实体对象时,使用的左外连接查询,一并查询出关联的对象,并已经进行初始化
        Manager mgr = (Manager)session.get(Manager.class, 1);
        System.out.println(mgr.getMgrName());
    }
}

  再说说多对一。

  N-1关联:

  顾客和订单,一个顾客对应多个订单。

    单向N-1:

  Custom类

package ntoone;

public class Customer {
    private int customerId;
    private String customerName;
    
    public int getCustomerId() {
        return customerId;
    }
    public void setCustomerId(int customerId) {
        this.customerId = customerId;
    }
    public String getCustomerName() {
        return customerName;
    }
    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }
}

  Order类

package ntoone;

public class Order {
    private int orderId;
    private String orderName;
    private Customer customer;
    
    public int getOrderId() {
        return orderId;
    }
    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }
    public String getOrderName() {
        return orderName;
    }
    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }
    public Customer getCustomer() {
        return customer;
    }
    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}

  Customer.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-22 15:13:00 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="ntoone.Customer" table="CUSTOMER">
        <id name="customerId" type="int">
            <column name="CUSTOMER_ID" />
            <generator class="native" />
        </id>
        <property name="customerName" type="java.lang.String">
            <column name="CUSTOMER_NAME" />
        </property>
    </class>
</hibernate-mapping>

  Order.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-22 15:13:00 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="ntoone">
    <class name="Order" table="ORDER">
        <id name="orderId" type="int">
            <column name="ORDER_ID" />
            <generator class="native" />
        </id>
        <property name="orderName" type="java.lang.String">
            <column name="ORDER_NAME" />
        </property>
        
        <!-- 映射多对一的关联关系,使用many-to-one来映射多对一一关联关系
            name:多这一端的一那一端的属性的名字
            class:一那一端的属性对应的类名
            column:一那一端在多的一端对应的数据表中的外键的名字
         -->
        <many-to-one name="customer" class="Customer" column="CUSTOMER_ID">
        </many-to-one>
    </class>
</hibernate-mapping>

  多的一端维护关联关系。想起一个故事,为什么要用多的一端维护关联关系,就好像一个部门里的人,有一个经理和很多职员,让经理记住每个职员的名字很难,但让职员记住经理的名字就很容易,这就是为什么单向多对一要让多的一端维护关联关系。

  HibernateTest类

package ntoone;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {
    private SessionFactory sessionFactory;
    
    private Session session;
    
    private Transaction transaction;
    
    @Before
    public void init()
    {
        System.out.println("init");

        // 1. 创建一个SessionFactory对象
        sessionFactory = null;
        Configuration configuration = new Configuration().configure();
        
        // before 4.0
//        sessionFactory = configuration.buildSessionFactory();
        
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
                                                                      .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        // 2. 创建一个Session 对象
        session = sessionFactory.openSession();
        
        // 3. 开启事务
        transaction = session.beginTransaction();
        
    }
    
    @After
    public void destory()
    {
        System.out.println("destory");
        // 5. 提交事务
        transaction.commit();
        
        // 6. 关闭Session
        session.close();
        
        // 7. 关闭SesssionFactory
        sessionFactory.close();
    }
    
    @Test
    public void testManyToOne()
    {
        Customer customer = new Customer();
        customer.setCustomerName("BB");
        
        Order order1 = new Order();
        order1.setOrderName("order-3");
        
        Order order2 = new Order();
        order2.setOrderName("order-4");
        
        // 设定关联关系
        order1.setCustomer(customer);
        order2.setCustomer(customer);
        
        // 执行save操作:先插入Customer, 再插入Order, 3条insert
        // 先插入1的一端,再插入n的一端,只有insert语句
//        session.save(customer);
//        session.save(order1);
//        session.save(order2);
        
        // 插入多的一端后,再插入一的一端,此时要更新多的一端的customerId,影响效率
        session.save(order1);
        session.save(order2);
        session.save(customer);
    }
    
    /**
     * 1. 若查询多的一端的一个对象,则默认情况下只查询了多的一端的对象,而没有查询关联的一的那
     *           一端的对象(延迟加载)
     * 2. 在需要使用到关联的对象时,才发送对应的SQL语句
     * 3. 在查询Customer对象时,由多一端导航到1的一端时,若
     *           session已经被关闭,会
     *           发生懒加载异常
     * 4. 获取Order对象时默认情况下,其关联的Customer对象是一个
     *    代理对象
     */
    @Test
    public void testMany2OneGet()
    {
        Order order = (Order) session.get(Order.class, 1);
        System.out.println(order.getOrderName());
        
        System.out.println(order.getCustomer().getClass());
        session.close();
        
        Customer customer = order.getCustomer();
        System.out.println(customer.getCustomerName());
    }
    
    @Test
    public void testUpdate()
    {
        Order order = (Order)session.get(Order.class, 1);
        order.getCustomer().setCustomerName("AAA");
    }
    
    public void testDelete()
    {
        // 在不设定级联关系的情况下,1这一端的对象有多的一端的对象在引用,
        // 不能直接删除1的一端的对象
        Customer customer = (Customer)session.get(Customer.class, 1);
        session.delete(customer);
    }
}

     双向N-1:

  Customer类:

package ntoone.both;

import java.util.HashSet;
import java.util.Set;

public class Customer {
    private int customerId;
    private String customerName;
    
    /**
     * 1.需要把集合进行初始化,防止出现空指针异常
     * 2.声明集合类型时需使用接口类型,因为hibernate在获取
     * 集合类型时,返回的是Hibernate内置的集合类型,而不是javaSE
     * 一个标准的集合实现
     */
    private Set<Order> orders = new HashSet<Order>();
    
    public Set<Order> getOrders() {
        return orders;
    }
    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }
    public int getCustomerId() {
        return customerId;
    }
    public void setCustomerId(int customerId) {
        this.customerId = customerId;
    }
    public String getCustomerName() {
        return customerName;
    }
    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }
}

  Order类:

package ntoone.both;

public class Order {
    private int orderId;
    private String orderName;
    private Customer customer;
    
    public int getOrderId() {
        return orderId;
    }
    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }
    public String getOrderName() {
        return orderName;
    }
    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }
    public Customer getCustomer() {
        return customer;
    }
    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}

  Customer.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-22 16:58:35 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="ntoone.both">
    <class name="Customer" table="CUSTOMER">
        <id name="customerId" type="int">
            <column name="CUSTOMER_ID" />
            <generator class="native" />
        </id>
        <property name="customerName" type="java.lang.String">
            <column name="CUSTOMER_NAME" />
        </property>
        <set name="orders" table="ORDER" inverse="true" cascade="save-update" order-by="ORDER_NAME DESC">
            <key>
                <column name="CUSTOMER_ID" />
            </key>
            <one-to-many class="Order" />
        </set>
    </class>
</hibernate-mapping>

  Order.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-22 16:58:35 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="ntoone.both">
    <class name="Order" table="ORDER">
        <id name="orderId" type="int">
            <column name="ORDER_ID" />
            <generator class="native" />
        </id>
        <property name="orderName" type="java.lang.String">
            <column name="ORDER_NAME" />
        </property>
        <many-to-one name="customer" class="Customer" column="CUSTOMER_ID">
        </many-to-one>
    </class>
</hibernate-mapping>

  这是双向一对多关联,一的一端通过指定自身的键值确定关联的多的一端,多的一端通过一的一端的键值确定关联的一的一端。

  HibernateTest类

package ntoone.both;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {
    private SessionFactory sessionFactory;
    
    private Session session;
    
    private Transaction transaction;
    
    @Before
    public void init()
    {
        System.out.println("init");

        // 1. 创建一个SessionFactory对象
        sessionFactory = null;
        Configuration configuration = new Configuration().configure();
        
        // before 4.0
//        sessionFactory = configuration.buildSessionFactory();
        
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
                                                                      .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        // 2. 创建一个Session 对象
        session = sessionFactory.openSession();
        
        // 3. 开启事务
        transaction = session.beginTransaction();
        
    }
    
    @After
    public void destory()
    {
        System.out.println("destory");
        // 5. 提交事务
        transaction.commit();
        
        // 6. 关闭Session
        session.close();
        
        // 7. 关闭SesssionFactory
        sessionFactory.close();
    }
    
    @Test
    public void testMany2OneSave()
    {
        Customer customer = new Customer();
        customer.setCustomerName("BB");
        
        Order order1 = new Order();
        order1.setOrderName("order-5");
        
        Order order2 = new Order();
        order2.setOrderName("order-6");
        
        // 设定关联关系
        order1.setCustomer(customer);
        order2.setCustomer(customer);
        
        customer.getOrders().add(order1);
        customer.getOrders().add(order2);
        
        // 因为1的一端也要维护关联关系,所以会多出UPDATE
        // 可以在1的一端的set节点指定inverse=true,来使1的一端放弃
        // 关联关系,建议设定set的inverse=true,且先插入1的一端,后
        // 插入多的一端,好处是不会多出update语句
        session.save(customer);
        session.save(order1);
        session.save(order2);
        
        // 
//        session.save(order1);
//        session.save(order2);
//        session.save(customer);
    }
    
    @Test
    public void testOne2ManyGet()
    {
        // 1. 对n的一端的集合使用延迟加载
        Customer customer = (Customer)session.get(Customer.class, 1);
        System.out.println(customer.getCustomerName());
        
//        session.close();
        //3.可能会抛出LazyInitializationException异常
        
        // 2. 返回的多的一端的集合时Hibernate内置的集合类型
        // 该类型具有延迟加载和存放代理对象的功能
        System.out.println(customer.getOrders().getClass());
        
        //4. 在需要使用集合中元素的时候再进行初始化
        // 下面就不会初始化,而只是发送一条count语句
        System.out.println(customer.getOrders().size());
    }
    
    @Test
    public void testUpdate()
    {
        Customer customer = (Customer)session.get(Customer.class, 1);
        customer.getOrders().iterator().next().setOrderName("BBB");
    }
}

  再说说多对多

  N-N:

   Category类:

package nton;

import java.util.HashSet;
import java.util.Set;

public class Category {
    private Integer id;
    private String name;
    private Set<Item> items = new HashSet<Item>();
    
    public Set<Item> getItems() {
        return items;
    }
    public void setItems(Set<Item> items) {
        this.items = items;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

  Item类:

package nton;

import java.util.HashSet;
import java.util.Set;

public class Item {
    private Integer id;
    private String name;
    private Set<Category> categories = new HashSet<Category>();
    public Set<Category> getCategories() {
        return categories;
    }
    public void setCategories(Set<Category> categories) {
        this.categories = categories;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

  Category.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-23 10:55:34 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="nton">
    <class name="Category" table="CATEGORY">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        
        <!-- table:指定中间表 -->
        <set name="items" table="CATEGORY_ITEM">
            <key>
                <column name="C_ID" />
            </key>
            <!-- 使用many-to-many指定多对多的关联关系,column执行set集合
                中的持久化类在中间表的外键列的名称
             -->
            <many-to-many class="Item" column="I_ID"/>
        </set>
    </class>
</hibernate-mapping>

  Item.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-7-23 10:55:34 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="nton">
    <class name="Item" table="ITEM">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        
        <set table="CATEGORY_ITEM" name="categories" inverse="true">
            <key column="I_ID"></key>
            <many-to-many class="Category" column="C_ID"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

       这是双向多对多关联,双方各自用一个set存储关联的一方,需要通过一个中间表来确定关联的一方,中间表存储双方的键值,通过一方的键值,可以找到关联的另一方。关于单向多对一,可以看上面提供的链接。

  好了,关联关系就说的差不多了,不全面,有些没说,我只是按照我代码中的来说的,对于单向的一对一和单向的多对多,可以看下我上面给的链接。

  最后是代码:hibernate_atguigu代码


亲爱的读者:有时间可以点赞评论一下

点赞(0) 打赏

全部评论

还没有评论!