zoukankan      html  css  js  c++  java
  • hibernate基于注解的维护权反转:@OneToMany(mappedBy=)

    背景说明:首先是SSH环境下,对象基于注解的方式映射到数据库;

    昨天遇到一个比较纠结的问题,@OneToMany(mappedBy="xxx"), mappedBy属性有什么用,然后是写在哪一边?

    还有一个问题是:@JoinColumn(name="xxxxx"),JoinColumn有什么用?

    先贴出最初的代码:一些基本的注解,在一对多的关系上没有使用JoinColumn和mappedBy属性

    部门类:主要是第33、34行

    复制代码
     1 package com.lizhou.entity.test;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 import javax.persistence.Column;
     7 import javax.persistence.Entity;
     8 import javax.persistence.GeneratedValue;
     9 import javax.persistence.GenerationType;
    10 import javax.persistence.Id;
    11 import javax.persistence.OneToMany;
    12 import javax.persistence.Table;
    13 
    14 import org.hibernate.annotations.GenericGenerator;
    15 
    16 /**
    17  * 部门:与员工一对多关系
    18  * @author bojiangzhou
    19  *
    20  */
    21 @Entity
    22 @Table(name="department")
    23 public class Department {
    24     
    25     @Id
    26     @GeneratedValue(generator="_native")
    27     @GenericGenerator(name="_native", strategy="native")
    28     private int id; //ID
    29     
    30     @Column(length=20)
    31     private String dname; //部门名称
    32     
    33     @OneToMany
    34     private List<Employee> employeeList = new ArrayList<>(); //部门下的员工集合
    35 
    36     // get/set方法59     
    60 }
    复制代码

    员工类:主要是第32、33行

    复制代码
     1 package com.lizhou.entity.test;
     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.ManyToOne;
     8 import javax.persistence.Table;
     9 
    10 import org.hibernate.annotations.GenericGenerator;
    11 
    12 /**
    13  * 员工:与部门多对一关系
    14  * @author bojiangzhou
    15  *
    16  */
    17 @Entity
    18 @Table(name="employee")
    19 public class Employee {
    20 
    21     @Id
    22     @GeneratedValue(generator="_native")
    23     @GenericGenerator(name="_native", strategy="native")
    24     private int id; //ID
    25     
    26     @Column(length=20)
    27     private String ename; //员工姓名
    28     
    29     @Column(length=20)
    30     private String phone; //电话
    31     
    32     @ManyToOne
    33     private Department department; //所属部门
    34     
    35     
    36     //get/set方法67     
    68 }
    复制代码

    最初的注解配置里,在一对多的关系上,即employeeList和department没有使用JoinColumn。

    看下图,employee表会自动添加一个外键列department_id,虽然关系映射上是正确了,但是有一个问题,数据库里多了一张表出来,这不是想要的结果。

    解决方法:在employeeList和department字段上加上@JoinColumn注解

    1 @OneToMany
    2 @JoinColumn(name="departmentId")
    3 private List<Employee> employeeList = new ArrayList<>(); //部门下的员工集合
    1 @ManyToOne//
    2 @JoinColumn(name="departmentId")//
    3 private Department department; //所属部门

    这样一来的话就只有两张表了,所以在一对多或者一对一的关系下,需要加上@JoinColumn来指定外键列,避免生成一张中间表。

    而且经试验,多的一方(Employee)里的department必须加上@JoinColumn,Department里不加不会影响表的结构,不知道会不会有其它影响;

    但是如果Employee属于多的一方,如果没有指定外键列,还是会自动生成一个department_id外键列。

    接下来讨论mappedBy属性:mappedBy属性主要是针对外键而言。与之相对应的是xml中的inverse属性。

    如下是测试类代码:此时还没有设置mappedBy属性,映射时,默认是都由自身维护关联关系。

    复制代码
     1 package com.lizhou.action.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.Transaction;
     6 import org.hibernate.cfg.Configuration;
     7 import org.junit.Test;
     8 import org.springframework.context.ApplicationContext;
     9 import org.springframework.context.support.ClassPathXmlApplicationContext;
    10 
    11 import com.lizhou.entity.test.Department;
    12 import com.lizhou.entity.test.Employee;
    13 
    14 /**
    15  * 测试类
    16  * @author bojiangzhou
    17  *
    18  */
    19 
    20 public class TestAction {
    21     
    22     private static SessionFactory sessionFactory = null;
    23     
    24     static {
    25         //读取classpath中applicationContext.xml配置文件
    26         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    27         //获取session中配置的sessionFactory对象
    28         sessionFactory = (SessionFactory) applicationContext.getBean("sessionFactory");
    29     }
    30     
    31     @Test
    32     public void testSave(){
    33         //创建一个部门对象
    34         Department d1 = new Department();
    35         d1.setDname("研发部");
    36         
    37         //创建两个员工对象
    38         Employee e1 = new Employee();
    39         e1.setEname("张三");
    40         e1.setPhone("13111111111");
    41         Employee e2 = new Employee();
    42         e2.setEname("李四");
    43         e2.setPhone("18523222222");
    44         
    45         //设置对象关联
    46         d1.getEmployeeList().add(e1);
    47         d1.getEmployeeList().add(e2);
    48         e1.setDepartment(d1);
    49         e2.setDepartment(d1);
    50         
    51         //获取Session
    52         Session session = sessionFactory.openSession();
    53         //开始事务
    54         Transaction t = session.beginTransaction();
    55         try {
    56             //添加数据
    57             session.save(d1);
    58             session.save(e1);
    59             session.save(e2);
    60             //提交事务
    61             t.commit();
    62         } catch (RuntimeException e) {
    63             //有异常则回滚事务
    64             t.rollback();
    65             e.printStackTrace();
    66         } finally {
    67             //关闭session
    68             session.close();
    69         }
    70     }
    71     
    72     
    73 }
    复制代码

    执行testSave后,控制台打印如下语句:

    1 Hibernate: insert into department (dname) values (?)
    2 Hibernate: insert into employee (departmentId, ename, phone) values (?, ?, ?)
    3 Hibernate: insert into employee (departmentId, ename, phone) values (?, ?, ?)
    4 Hibernate: update employee set departmentId=? where id=?
    5 Hibernate: update employee set departmentId=? where id=?

    可以看到多了两条update语句,这是因为两边都维护关系,先插入的部门,再插入员工,插入员工时,已经设置好外键了,但部门方也维护关系,会再执行一次更新操作,为员工设置外键,这样就导致多出了两条update语句,这里是有性能损耗的。

    一种解决办法是:将第46、47行去掉,即对象上部门不关联员工

    复制代码
     1 package com.lizhou.action.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.Transaction;
     6 import org.hibernate.cfg.Configuration;
     7 import org.junit.Test;
     8 import org.springframework.context.ApplicationContext;
     9 import org.springframework.context.support.ClassPathXmlApplicationContext;
    10 
    11 import com.lizhou.entity.test.Department;
    12 import com.lizhou.entity.test.Employee;
    13 
    14 /**
    15  * 测试类
    16  * @author bojiangzhou
    17  *
    18  */
    19 
    20 public class TestAction {
    21     
    22     private static SessionFactory sessionFactory = null;
    23     
    24     static {
    25         //读取classpath中applicationContext.xml配置文件
    26         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    27         //获取session中配置的sessionFactory对象
    28         sessionFactory = (SessionFactory) applicationContext.getBean("sessionFactory");
    29     }
    30     
    31     @Test
    32     public void testSave(){
    33         //创建一个部门对象
    34         Department d1 = new Department();
    35         d1.setDname("研发部");
    36         
    37         //创建两个员工对象
    38         Employee e1 = new Employee();
    39         e1.setEname("张三");
    40         e1.setPhone("13111111111");
    41         Employee e2 = new Employee();
    42         e2.setEname("李四");
    43         e2.setPhone("18523222222");
    44         
    45         //设置对象关联
    46 //        d1.getEmployeeList().add(e1);
    47 //        d1.getEmployeeList().add(e2);
    48         e1.setDepartment(d1);
    49         e2.setDepartment(d1);
    50         
    51         //获取Session
    52         Session session = sessionFactory.openSession();
    53         //开始事务
    54         Transaction t = session.beginTransaction();
    55         try {
    56             //添加数据
    57             session.save(d1);
    58             session.save(e1);
    59             session.save(e2);
    60             //提交事务
    61             t.commit();
    62         } catch (RuntimeException e) {
    63             //有异常则回滚事务
    64             t.rollback();
    65             e.printStackTrace();
    66         } finally {
    67             //关闭session
    68             session.close();
    69         }
    70     }
    71     
    72     
    73 }
    复制代码
    1 Hibernate: insert into department (dname) values (?)
    2 Hibernate: insert into employee (departmentId, ename, phone) values (?, ?, ?)
    3 Hibernate: insert into employee (departmentId, ename, phone) values (?, ?, ?)

    这样部门方就不会去维护外键关系了。但是有一个问题,对象上就没有关联了,我们要做的是对象上要互相关联,数据库方面只让一方去维护关系即可。

    对象上如果不关联,因为部门和员工添加到数据库后,是持久化状态,存在于session缓存中,那session操作缓存中这几个对象时,部门就没有关联员工了,那么就还得再查询一次数据库,这不是想要的结果。

    这时就要用到mappedBy属性了。

    在一的一方配置@OneToMany(mappedBy="department"),将维护权交由多的一方来维护;

    那为什么不让多的一方交出维护权,让一的一方来维护呢?上面的实验也表明了如果让一的一方来维护,始终都会多出两条update语句,因为外键是在多的这一方的,所以维护权应该交由多的一方。

    部门类的配置:第36行和第37行的配置,部门部门交出维护权利,让对方来维护

    复制代码
     1 package com.lizhou.entity.test;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 import javax.persistence.CascadeType;
     7 import javax.persistence.Column;
     8 import javax.persistence.Entity;
     9 import javax.persistence.FetchType;
    10 import javax.persistence.GeneratedValue;
    11 import javax.persistence.GenerationType;
    12 import javax.persistence.Id;
    13 import javax.persistence.JoinColumn;
    14 import javax.persistence.OneToMany;
    15 import javax.persistence.Table;
    16 
    17 import org.hibernate.annotations.GenericGenerator;
    18 
    19 /**
    20  * 部门:与员工一对多关系
    21  * @author bojiangzhou
    22  *
    23  */
    24 @Entity
    25 @Table(name="department")
    26 public class Department {
    27     
    28     @Id
    29     @GeneratedValue(generator="_native")
    30     @GenericGenerator(name="_native", strategy="native")
    31     private int id; //ID
    32     
    33     @Column(length=20)
    34     private String dname; //部门名称
    35     
    36     @OneToMany(mappedBy="department")
    37     private List<Employee> employeeList = new ArrayList<>(); //部门下的员工集合
    38 
    39     // get/set方法62     
    63 }
    复制代码

    员工类的配置不变。

    调用testSave时,部门和员工再对象上依然是关联的:第46-49行

    复制代码
     1 package com.lizhou.action.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.Transaction;
     6 import org.hibernate.cfg.Configuration;
     7 import org.junit.Test;
     8 import org.springframework.context.ApplicationContext;
     9 import org.springframework.context.support.ClassPathXmlApplicationContext;
    10 
    11 import com.lizhou.entity.test.Department;
    12 import com.lizhou.entity.test.Employee;
    13 
    14 /**
    15  * 测试类
    16  * @author bojiangzhou
    17  *
    18  */
    19 
    20 public class TestAction {
    21     
    22     private static SessionFactory sessionFactory = null;
    23     
    24     static {
    25         //读取classpath中applicationContext.xml配置文件
    26         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    27         //获取session中配置的sessionFactory对象
    28         sessionFactory = (SessionFactory) applicationContext.getBean("sessionFactory");
    29     }
    30     
    31     @Test
    32     public void testSave(){
    33         //创建一个部门对象
    34         Department d1 = new Department();
    35         d1.setDname("研发部");
    36         
    37         //创建两个员工对象
    38         Employee e1 = new Employee();
    39         e1.setEname("张三");
    40         e1.setPhone("13111111111");
    41         Employee e2 = new Employee();
    42         e2.setEname("李四");
    43         e2.setPhone("18523222222");
    44         
    45         //设置对象关联
    46         d1.getEmployeeList().add(e1);
    47         d1.getEmployeeList().add(e2);
    48         e1.setDepartment(d1);
    49         e2.setDepartment(d1);
    50         
    51         //获取Session
    52         Session session = sessionFactory.openSession();
    53         //开始事务
    54         Transaction t = session.beginTransaction();
    55         try {
    56             //添加数据
    57             session.save(d1);
    58             session.save(e1);
    59             session.save(e2);
    60             //提交事务
    61             t.commit();
    62         } catch (RuntimeException e) {
    63             //有异常则回滚事务
    64             t.rollback();
    65             e.printStackTrace();
    66         } finally {
    67             //关闭session
    68             session.close();
    69         }
    70     }
    71     
    72     
    73 }
    复制代码

    控制台打印的语句:只有三条插入语句,没有更新语句了

    1 Hibernate: insert into department (dname) values (?)
    2 Hibernate: insert into employee (departmentId, ename, phone) values (?, ?, ?)
    3 Hibernate: insert into employee (departmentId, ename, phone) values (?, ?, ?)

    这里遇到一个问题:如果配置mappedBy属性的同时加上@JoinColumn会抛出异常,所以不能同时使用@JoinColumn和mappedBy;因为@JoinColumn本身就是自己来维护外键,和mappedBy冲突了。--->>>不知道这样理解正确否!!^_^

    复制代码
     1 package com.lizhou.entity.test;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 import javax.persistence.CascadeType;
     7 import javax.persistence.Column;
     8 import javax.persistence.Entity;
     9 import javax.persistence.FetchType;
    10 import javax.persistence.GeneratedValue;
    11 import javax.persistence.GenerationType;
    12 import javax.persistence.Id;
    13 import javax.persistence.JoinColumn;
    14 import javax.persistence.OneToMany;
    15 import javax.persistence.Table;
    16 
    17 import org.hibernate.annotations.GenericGenerator;
    18 
    19 /**
    20  * 部门:与员工一对多关系
    21  * @author bojiangzhou
    22  *
    23  */
    24 @Entity
    25 @Table(name="department")
    26 public class Department {
    27     
    28     @Id
    29     @GeneratedValue(generator="_native")
    30     @GenericGenerator(name="_native", strategy="native")
    31     private int id; //ID
    32     
    33     @Column(length=20)
    34     private String dname; //部门名称
    35     
    36     @OneToMany(mappedBy="department")
    37     @JoinColumn(name="departmentId")
    38     private List<Employee> employeeList = new ArrayList<>(); //部门下的员工集合
    39 
    40     // set/get 方法63     
    64 }
    复制代码

    抛出如下异常:

    复制代码
     1 java.lang.ExceptionInInitializerError
     2     at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
     3     at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
     4     at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
     5     at java.lang.reflect.Constructor.newInstance(Unknown Source)
     6     at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
     7     at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
     8     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
     9     at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
    10     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    11     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    12     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    13     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    14     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    15     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    16     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    17     at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    18     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    19     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    20     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    21     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    22     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    23     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
    24 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: com.lizhou.entity.test.Department.employeeList
    25     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
    26     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
    27     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    28     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    29     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    30     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    31     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    32     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:684)
    33     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
    34     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    35     at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    36     at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    37     at com.lizhou.action.test.TestAction.<clinit>(TestAction.java:26)
    38     ... 22 more
    39 Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: com.lizhou.entity.test.Department.employeeList
    40     at org.hibernate.cfg.annotations.CollectionBinder.bind(CollectionBinder.java:493)
    41     at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2156)
    42     at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:963)
    43     at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:796)
    44     at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3788)
    45     at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3742)
    46     at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1410)
    47     at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
    48     at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
    49     at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:343)
    50     at org.springframework.orm.hibernate4.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:431)
    51     at org.springframework.orm.hibernate4.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:416)
    52     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
    53     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
    54     ... 34 more
    复制代码

    还有一点说明下:

    如果将第57行代码移到第59行后面,即先保存员工,再保存部门,会多出四条update语句

    复制代码
     1 package com.lizhou.action.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.Transaction;
     6 import org.hibernate.cfg.Configuration;
     7 import org.junit.Test;
     8 import org.springframework.context.ApplicationContext;
     9 import org.springframework.context.support.ClassPathXmlApplicationContext;
    10 
    11 import com.lizhou.entity.test.Department;
    12 import com.lizhou.entity.test.Employee;
    13 
    14 /**
    15  * 测试类
    16  * @author bojiangzhou
    17  *
    18  */
    19 
    20 public class TestAction {
    21     
    22     private static SessionFactory sessionFactory = null;
    23     
    24     static {
    25         //读取classpath中applicationContext.xml配置文件
    26         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    27         //获取session中配置的sessionFactory对象
    28         sessionFactory = (SessionFactory) applicationContext.getBean("sessionFactory");
    29     }
    30     
    31     @Test
    32     public void testSave(){
    33         //创建一个部门对象
    34         Department d1 = new Department();
    35         d1.setDname("研发部");
    36         
    37         //创建两个员工对象
    38         Employee e1 = new Employee();
    39         e1.setEname("张三");
    40         e1.setPhone("13111111111");
    41         Employee e2 = new Employee();
    42         e2.setEname("李四");
    43         e2.setPhone("18523222222");
    44         
    45         //设置对象关联
    46         d1.getEmployeeList().add(e1);
    47         d1.getEmployeeList().add(e2);
    48         e1.setDepartment(d1);
    49         e2.setDepartment(d1);
    50         
    51         //获取Session
    52         Session session = sessionFactory.openSession();
    53         //开始事务
    54         Transaction t = session.beginTransaction();
    55         try {
    56             //添加数据
    57             session.save(e1);
    58             session.save(e2);
    59             session.save(d1);
    60             //提交事务
    61             t.commit();
    62         } catch (RuntimeException e) {
    63             //有异常则回滚事务
    64             t.rollback();
    65             e.printStackTrace();
    66         } finally {
    67             //关闭session
    68             session.close();
    69         }
    70     }
    71     
    72     
    73 }
    复制代码
    复制代码
    1 Hibernate: insert into employee (departmentId, ename, phone) values (?, ?, ?)
    2 Hibernate: insert into employee (departmentId, ename, phone) values (?, ?, ?)
    3 Hibernate: insert into department (dname) values (?)
    4 Hibernate: update employee set departmentId=?, ename=?, phone=? where id=?
    5 Hibernate: update employee set departmentId=?, ename=?, phone=? where id=?
    6 Hibernate: update employee set departmentId=? where id=?
    7 Hibernate: update employee set departmentId=? where id=?
    复制代码

    很明显,在插入员工时,还没有部门的信息,等插入部门的时候,员工方会维护外键关系,更新外键;而部门方也会维护一次,所以多了四条语句。所以在添加数据的时候先保存一的一方,再保存多的一方。

    总结:mappedBy属性跟xml配置文件里的inverse一样。在一对多或一对一的关系映射中,如果不表明mappedBy属性,默认是由本方维护外键。但如果两方都由本方来维护的话,会多出一些update语句,性能有一定的损耗。

    解决的办法就是在一的一方配置上mappedBy属性,将维护权交给多的一方来维护,就不会有update语句了。

    至于为何要将维护权交给多的一方,可以这样考虑:要想一个国家的领导人记住所有人民的名字是不可能的,但可以让所有人民记住领导人的名字!

    注意,配了mappedBy属性后,不要再有@JoinColumn,会冲突!

    OK!!!

  • 相关阅读:
    JOI2017FinalC JOIOI 王国
    JOISC2017C 手持ち花火
    P4336 [SHOI2016]黑暗前的幻想乡
    SP104 HIGH
    P3160 [CQOI2012]局部极小值
    P4965 薇尔莉特的打字机
    【BZOJ4361】isn
    P3506 [POI2010]MOT-Monotonicity 2
    P3214 [HNOI2011]卡农
    P3704 [SDOI2017]数字表格
  • 原文地址:https://www.cnblogs.com/wangchaoyuana/p/7523293.html
Copyright © 2011-2022 走看看