• 9、JPA_映射双向一对一的关联关系


    双向一对一的关联关系

    举例说明:经理Manager和部门Department是双向一对一关联关系。则Manager实体类中有Department实体对象的引用,反之亦然。

    其实体属性定义如下:

    List_1. Manager实体类属性定义(有对Department实体对象的引用)
     1 @Table(name="t_manager")
     2 @Entity
     3 public class Manager {
     4     
     5     private Integer id;
     6     private String mgrName;
     7     
     8     //有对实体Department对象的引用
     9     private Department dept;
    10 
    11     //省略getter、setter方法...
    12 }
    List_2. Department实体类属性定义(有对Manager实体对象的引用)
     1 @Table(name="t_department")
     2 @Entity
     3 public class Department {
     4     
     5     private Integer id;
     6     private String deptName;
     7     
     8     //有对Manager实体对象的引用
     9     private Manager mgr;
    10 
    11     //省略getter、setter方法...
    12 
    13 }

    双向一对一的关联关系映射方法有两种:基于外键的映射、基于主键的映射。

    这里讲使用较多的基于外键的映射。其映射步骤如下(例子中假定由Manager一方维护关联关系,Department一方放弃维护关联关系):

    1、双方都使用使用@OneToOne注解来映射关联关系;

    2、只需要一方维护关联关系(任何一方都可以):

         ①、放弃维护关联关系的一方需要配置@OneToOne的mappedBy属性,用于指定由对方的哪个属性来映射,同时不能使用@JoinColum注解(和前面讲的双向一对多关联关系是一样的)。放弃维护关联关系的一方所对应的数据表没有外键列。如下Department实体中的映射注解:

    List_3. Department实体类的映射注解(放弃维护关联关系,指定由对方的dept属性来进行关联;不能使用@JoinColumn注解)
    @OneToOne(mappedBy="dept")
    public Manager getMgr() {
        return mgr;
    }

         ②、维护关联的一方需要使用@JoinColumn注解来指定外键列的列名,同时还要指定外键列的唯一约束:@JoinColumn(name="DEPT_ID", unique=true)。维护关联关系的一方实体对应的数据表有一个外键列,列名由name属性指定。如下Manager实体类中的映射注解:

    List_4. Manager实体类的映射注解(由@JoinColumn注解的name属性指定表的外键列的列名,同时指定外键列的唯一约束)
    @JoinColumn(name="DEPT_ID", unique=true)
    @OneToOnepublic Department getDept() {
        return dept;
    }

    再讲一下映射的默认属性,同上面一样由Manager一方维护关联关系:

    1、默认情况下,双方对实体类对象的引用均采用立即加载的检索策略,这是符合前面 8、双向一对多关联关系 一节所阐述的“默认情况下,对象属性采用立即检索,集合属性采用延迟检索”。

    2、修改默认检索策略:

         ①、维护关联关系的一方(如Manager)所对应的数据表有外键列,可以通过设置@OneToOne的属性fetch=FetchType.LAZY来设置延迟加载策略。

         ②、放弃维护关联关系的一方(如Department)所对应的数据表中没有外键,即便设置了fetch=FetchType.LAZY也不能够达到延迟加载的效果。相反,如果设置了fetch=FetchType.LAZY以后还会多发送一条sql语句(两条select语句);没有设置的时候,只发送一条sql语句(一条带left outer join的select语句)。

    3、保存顺序,先保存放弃维护关联关系的一方实体,后保存维护关联关系的一方实体。这样可以避免发送update语句。

    下面是实验代码清单:

    List_5. Department实体(放弃维护关联关系,指定由对方的dept属性来进行关联;不能使用@JoinColumn注解)

     1 package com.magicode.jpa.doubl.one2one;
     2 
     3 import javax.persistence.Column;
     4 import javax.persistence.Entity;
     5 import javax.persistence.GeneratedValue;
     6 import javax.persistence.Id;
     7 import javax.persistence.OneToOne;
     8 import javax.persistence.Table;
     9 
    10 @Table(name="t_department")
    11 @Entity
    12 public class Department {
    13     
    14     private Integer id;
    15     private String deptName;
    16     
    17     private Manager mgr;
    18 
    19     @Column(name="ID")
    20     @GeneratedValue
    21     @Id
    22     public Integer getId() {
    23         return id;
    24     }
    25 
    26     @Column(name="DEPT_NAME", length=25)
    27     public String getDeptName() {
    28         return deptName;
    29     }
    30 
    31     /**
    32      * 通过mapptedBy指定由关联对象的那个属性建立起连接 
    33      * Manger实体对应的数据表没有外键,无法使用延迟加载策略
    34      * 所以使用默认的检索方式就好。
    35      * 如果设置了fetch=FetchType.LAZY反而会多发送一条sql语句。
    36      */
    37     @OneToOne(mappedBy="dept")
    38     public Manager getMgr() {
    39         return mgr;
    40     }
    41 
    42     @SuppressWarnings("unused")
    43     private void setId(Integer id) {
    44         this.id = id;
    45     }
    46 
    47     public void setDeptName(String deptName) {
    48         this.deptName = deptName;
    49     }
    50 
    51     public void setMgr(Manager mgr) {
    52         this.mgr = mgr;
    53     }
    54 }

    List_6. Manager实体(由@JoinColumn注解的name属性指定表的外键列的列名,同时指定外键列的唯一约束)

    package com.magicode.jpa.doubl.one2one;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.OneToOne;
    import javax.persistence.Table;
    
    @Table(name="t_manager")
    @Entity
    public class Manager {
        
        private Integer id;
        private String mgrName;
        
        private Department dept;
    
        @Column(name="ID")
        @GeneratedValue
        @Id
        public Integer getId() {
            return id;
        }
    
        @Column(name="MGR_NAME", length=25)
        public String getMgrName() {
            return mgrName;
        }
    
        /**
         * 默认情况下对Department属性的检索采用立即检索策略。
         * 由于Manager实体对应的数据表有外键列,所以可以设置
         * fetch=FetchType.LAZY来修改为延迟加载策略。
         * 
         * 注意:对没有外键类的一方(Department一方)则无法实现
         * 延迟加载策略。设置 fetch=FetchType.LAZY以后反而会
         * 多发送一条sql语句。
         */
        @JoinColumn(name="DEPT_ID", unique=true)
        @OneToOne(fetch=FetchType.LAZY)
        public Department getDept() {
            return dept;
        }
    
        @SuppressWarnings("unused")
        private void setId(Integer id) {
            this.id = id;
        }
    
        public void setMgrName(String mgrName) {
            this.mgrName = mgrName;
        }
    
        public void setDept(Department dept) {
            this.dept = dept;
        }
    
    }

    List_7. 测试代码:

    package com.magicode.jpa.doubl.one2one;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    public class DoubleOne2OneTest {
        
        private EntityManagerFactory emf = null;
        private EntityManager em = null;
        private EntityTransaction transaction = null;
        
        @Before
        public void before(){
            emf = Persistence.createEntityManagerFactory("jpa-1");
            em = emf.createEntityManager();
            transaction = em.getTransaction();
            transaction.begin();
        }
        
        @After
        public void after(){
            transaction.commit();
            em.close();
            emf.close();
        }
        
        @Test
        public void testPersist(){
            Department dept = new Department();
            dept.setDeptName("Dept-AA");
            
            Manager mgr = new Manager();
            mgr.setMgrName("Mgr-AA");
            
            //创建关联关系
            dept.setMgr(mgr);
            mgr.setDept(dept);
            
            /**
             * 持久化的时候,先持久化没有外键的那个对象,在持久化有
             * 外间的对象。这样就会避免发送update语句。
             */
            em.persist(dept);
            em.persist(mgr);
        }
        
        @Test
        public void testFind(){
            /**
             * 默认情况下,双向1-1关联关系中,在检索的时候都采用立即
             * 检索的策略(通过左外连接的方式查找与其相关联的属性)。
             * 
             * 有外键的那一方实体可以通过设置@OneToOne注解的fetch=FetchType.LAZY来
             * 修改默认检索策略。将其设置为延迟加载(对实体对象索引的检索)。
             * 
             * 对于没有外键的那一方而言,我们不需要修改其默认的检索方式。因为,无论你是否设置
             * fetch=FetchType.LAZY都会立即加载其关联的那一方实体(其没有对应的外键列,
             * 如果在检索的时候不加载,以后就无法找到其关联的实体对象了)。
             * 而且,如果设置了fetch=FetchType.LAZY还会稍微的有一点儿影响性能:默认情况下
             * 采用左外连接的方式,只会发送一条sql语句;而如果设置了fetch=FetchType.LAZY
             * 则会发送两条sql语句。
             */
    //        Manager mgr = em.find(Manager.class, 2);
    //        System.out.println(mgr.getMgrName());
    //        System.out.println(mgr.getDept().getClass().getName());
    //        
    //        System.out.println("--------------->");
            
            Department dept = em.find(Department.class, 3);
    //        System.out.println(dept.getDeptName());
    //        System.out.println(dept.getMgr().getClass().getName());
            
            
        }
    
    }
  • 相关阅读:
    如何成为伟大的程序员
    程序员如何增加收入
    一个阿里巴巴码农的六年回眸
    效仿盖茨:PPstream创始人的心路历程
    程序员的工作环境与效率
    软件级负载均衡器(LVS/HAProxy/Nginx)的特点简介和对比
    技术人员创业后就不再适合继续编码了
    互联网行业持续交付的经验
    11 款用于优化、分析源代码的Java工具
    常用 Java 静态代码分析工具的分析与比较
  • 原文地址:https://www.cnblogs.com/lj95801/p/5011137.html
Copyright © 2020-2023  润新知