映射单向一对多的关联关系

新建项目项目请参考《JPA(二):HellWord工程》,基于上一章讲解的《JPA(五):映射关联关系------映射单向多对一的关联关系》中的例子进行修改(需要清空数据中的表,因为本例子还是使用customer,order表来测试,但是关联关系发生了变化):

Customer.java

  1. package com.dx.jpa.singlemanytoone;
  2.  
  3. import java.util.Date;
  4. import java.util.HashSet;
  5. import java.util.Set;
  6.  
  7. import javax.persistence.Column;
  8. import javax.persistence.Entity;
  9. import javax.persistence.GeneratedValue;
  10. import javax.persistence.GenerationType;
  11. import javax.persistence.Id;
  12. import javax.persistence.JoinColumn;
  13. import javax.persistence.OneToMany;
  14. import javax.persistence.Table;
  15. import javax.persistence.Temporal;
  16. import javax.persistence.TemporalType;
  17. import javax.persistence.Transient;
  18.  
  19. @Entity
  20. @Table(name = "jpa_customer")
  21. public class Customer {
  22. private Integer id;
  23. private String fullName;
  24. private Integer age;
  25. private Date birth;
  26. private Date createDate;
  27. private Set<Order> orders = new HashSet<>();
  28.  
  29. @Id
  30. @GeneratedValue(strategy = GenerationType.AUTO)
  31. public Integer getId() {
  32. return id;
  33. }
  34.  
  35. public void setId(Integer id) {
  36. this.id = id;
  37. }
  38.  
  39. @Column(name = "FULL_NAME", length = 64, nullable = false)
  40. public String getFullName() {
  41. return fullName;
  42. }
  43.  
  44. public void setFullName(String fullName) {
  45. this.fullName = fullName;
  46. }
  47.  
  48. public Integer getAge() {
  49. return age;
  50. }
  51.  
  52. public void setAge(Integer age) {
  53. this.age = age;
  54. }
  55.  
  56. @Temporal(TemporalType.DATE)
  57. public Date getBirth() {
  58. return birth;
  59. }
  60.  
  61. public void setBirth(Date birth) {
  62. this.birth = birth;
  63. }
  64.  
  65. @Temporal(TemporalType.TIMESTAMP)
  66. public Date getCreateDate() {
  67. return createDate;
  68. }
  69.  
  70. public void setCreateDate(Date createDate) {
  71. this.createDate = createDate;
  72. }
  73.  
  74. // 映射一对多的关联关系
  75. // @JoinColumn 用来映射一对多的关联关系
  76. // @OneToMany 用来映射外键列
  77. @JoinColumn(name = "CUSTOMER_ID")
  78. @OneToMany()
  79. public Set<Order> getOrders() {
  80. return orders;
  81. }
  82.  
  83. public void setOrders(Set<Order> orders) {
  84. this.orders = orders;
  85. }
  86.  
  87. // 帮助方法,不希望保存到数据库,但是需要动态获取Customer对象的属性。
  88. @Transient
  89. public String getCustomerInfo() {
  90. return "username:" + fullName + ",age:" + age;
  91. }
  92. }

注意:这里在Customer.java中添加了一对多的注解@OneToMany:

  1. // 映射一对多的关联关系
  2. // @JoinColumn 用来映射一对多的关联关系
  3. // @OneToMany 用来映射外键列
  4. @JoinColumn(name = "CUSTOMER_ID")
  5. @OneToMany()
  6. public Set<Order> getOrders() {
  7. return orders;
  8. }

Order.java

  1. package com.dx.jpa.singlemanytoone;
  2.  
  3. import javax.persistence.Entity;
  4. import javax.persistence.GeneratedValue;
  5. import javax.persistence.GenerationType;
  6. import javax.persistence.Id;
  7. import javax.persistence.Table;
  8.  
  9. @Entity
  10. @Table(name = "jpa_order")
  11. public class Order {
  12. private Integer id;
  13. private String name;
  14.  
  15. @Id
  16. @GeneratedValue(strategy = GenerationType.AUTO)
  17. public Integer getId() {
  18. return id;
  19. }
  20.  
  21. public void setId(Integer id) {
  22. this.id = id;
  23. }
  24.  
  25. public String getName() {
  26. return name;
  27. }
  28.  
  29. public void setName(String name) {
  30. this.name = name;
  31. }
  32. }

初始化JPA项目时,创建表语句如下:

  1. Hibernate:
  2.  
  3. create table hibernate_sequence (
  4. next_val bigint
  5. ) engine=InnoDB
  6. Hibernate:
  7.  
  8. insert into hibernate_sequence values ( 1 )
  9. Hibernate:
  10.  
  11. insert into hibernate_sequence values ( 1 )
  12. Hibernate:
  13.  
  14. create table jpa_customer (
  15. id integer not null,
  16. age integer,
  17. birth date,
  18. createDate datetime,
  19. FULL_NAME varchar(64) not null,
  20. primary key (id)
  21. ) engine=InnoDB
  22. Hibernate:
  23.  
  24. create table jpa_order (
  25. id integer not null,
  26. name varchar(255),
  27. CUSTOMER_ID integer,
  28. primary key (id)
  29. ) engine=InnoDB
  30. Hibernate:
  31.  
  32. alter table jpa_order
  33. add constraint FK7glkngwj74nr8h2amofkp1fjd
  34. foreign key (CUSTOMER_ID)
  35. references jpa_customer (id)

persistence.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <persistence version="2.0"
  3. xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  5. <persistence-unit name="Jpa-helloword"
  6. transaction-type="RESOURCE_LOCAL">
  7. <!-- 配置使用什么 ORM 产品来作为 JPA 的实现 -->
  8. <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
  9. <!-- 添加持久化类 -->
  10. <class>com.dx.jpa.singlemanytoone.Customer</class>
  11. <class>com.dx.jpa.singlemanytoone.Order</class>
  12. <properties>
  13. <!-- 数据库的相关配置 -->
  14. <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
  15. <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/jpa" />
  16. <property name="javax.persistence.jdbc.user" value="root" />
  17. <property name="javax.persistence.jdbc.password" value="root" />
  18. <!-- 指定方言
  19. MySQL org.hibernate.dialect.MySQLDialect
  20. MySQL with InnoDB org.hibernate.dialect.MySQLInnoDBDialect
  21. MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect
  22. MySQL5 org.hibernate.dialect.MySQL5Dialect
  23. MySQL5 with InnoDB org.hibernate.dialect.MySQL5InnoDBDialect
  24. -->
  25. <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
  26. <property name="hibernate.show_sql" value="true" />
  27. <property name="hibernate.format_sql" value="true" />
  28. <!--
  29. create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。<br>
  30. create-drop :每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。<br>
  31. update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。<br>
  32. validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 <br>
  33. -->
  34. <property name="hibernate.hbm2ddl.auto" value="update" />
  35. </properties>
  36. </persistence-unit>
  37. </persistence>

此时在order表中创建了外键关联关系:

添加测试

添加测试函数:

  1. @Test
  2. public void testPersist() {
  3. Customer customer = new Customer();
  4. customer.setFullName("AA");
  5. customer.setAge(26);
  6. customer.setBirth(new Date());
  7. customer.setCreateDate(new Date());
  8.  
  9. Order order1 = new Order();
  10. order1.setName("O-AA-01");
  11.  
  12. Order order2 = new Order();
  13. order2.setName("O-AA-02");
  14.  
  15. customer.getOrders().add(order1);
  16. customer.getOrders().add(order2);
  17.  
  18. entityManager.persist(customer);
  19. entityManager.persist(order1);
  20. entityManager.persist(order2);
  21. }

此时执行sql如下:

  1. Hibernate:
  2. select
  3. next_val as id_val
  4. from
  5. hibernate_sequence for update
  6.  
  7. Hibernate:
  8. update
  9. hibernate_sequence
  10. set
  11. next_val= ?
  12. where
  13. next_val=?
  14. Hibernate:
  15. select
  16. next_val as id_val
  17. from
  18. hibernate_sequence for update
  19.  
  20. Hibernate:
  21. update
  22. hibernate_sequence
  23. set
  24. next_val= ?
  25. where
  26. next_val=?
  27. Hibernate:
  28. select
  29. next_val as id_val
  30. from
  31. hibernate_sequence for update
  32.  
  33. Hibernate:
  34. update
  35. hibernate_sequence
  36. set
  37. next_val= ?
  38. where
  39. next_val=?
  40. Hibernate:
  41. insert
  42. into
  43. jpa_customer
  44. (age, birth, createDate, FULL_NAME, id)
  45. values
  46. (?, ?, ?, ?, ?)
  47. Hibernate:
  48. insert
  49. into
  50. jpa_order
  51. (name, id)
  52. values
  53. (?, ?)
  54. Hibernate:
  55. insert
  56. into
  57. jpa_order
  58. (name, id)
  59. values
  60. (?, ?)
  61. Hibernate:
  62. update
  63. jpa_order
  64. set
  65. CUSTOMER_ID=?
  66. where
  67. id=?
  68. Hibernate:
  69. update
  70. jpa_order
  71. set
  72. CUSTOMER_ID=?
  73. where
  74. id=?

此时并不是因为customer,order保存顺序导致的(即使调换添加先后顺序也会多处update语句),因为多的一端在插入时不会插入外键列,因此一定会多处update语句。

查询测试

添加测试函数:

  1. @Test
  2. public void testFind() {
  3. Customer customer = entityManager.find(Customer.class, 1);
  4. System.out.println(customer.getFullName());
  5. System.out.println(customer.getOrders().size());
  6. }

执行打印结果:

  1. Hibernate:
  2. select
  3. customer0_.id as id1_0_0_,
  4. customer0_.age as age2_0_0_,
  5. customer0_.birth as birth3_0_0_,
  6. customer0_.createDate as createDa4_0_0_,
  7. customer0_.FULL_NAME as FULL_NAM5_0_0_
  8. from
  9. jpa_customer customer0_
  10. where
  11. customer0_.id=?
  12. AA
  13. Hibernate:
  14. select
  15. orders0_.CUSTOMER_ID as CUSTOMER3_1_0_,
  16. orders0_.id as id1_1_0_,
  17. orders0_.id as id1_1_1_,
  18. orders0_.name as name2_1_1_
  19. from
  20. jpa_order orders0_
  21. where
  22. orders0_.CUSTOMER_ID=?
  23. 2

从打印结果上可以看出默认采用懒加载的方式,修改Customer.java中的@OneToMany()中的fetch属性为:@OneToMany(fetch=FetchType.EAGER),此时才会出现非懒加载:

此时,再次执行插叙测试函数,执行打印结果如下:

  1. Hibernate:
  2. select
  3. customer0_.id as id1_0_0_,
  4. customer0_.age as age2_0_0_,
  5. customer0_.birth as birth3_0_0_,
  6. customer0_.createDate as createDa4_0_0_,
  7. customer0_.FULL_NAME as FULL_NAM5_0_0_,
  8. orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
  9. orders1_.id as id1_1_1_,
  10. orders1_.id as id1_1_2_,
  11. orders1_.name as name2_1_2_
  12. from
  13. jpa_customer customer0_
  14. left outer join
  15. jpa_order orders1_
  16. on customer0_.id=orders1_.CUSTOMER_ID
  17. where
  18. customer0_.id=?
  19. AA
  20. 2

修改测试

修改测试函数:

  1. @Test
  2. public void testUpdate() {
  3. Customer customer = entityManager.find(Customer.class, 1);
  4. customer.getOrders().iterator().next().setName("O-XX-01");
  5. }

此时执行打印结果为:

  1. Hibernate:
  2. select
  3. customer0_.id as id1_0_0_,
  4. customer0_.age as age2_0_0_,
  5. customer0_.birth as birth3_0_0_,
  6. customer0_.createDate as createDa4_0_0_,
  7. customer0_.FULL_NAME as FULL_NAM5_0_0_,
  8. orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
  9. orders1_.id as id1_1_1_,
  10. orders1_.id as id1_1_2_,
  11. orders1_.name as name2_1_2_
  12. from
  13. jpa_customer customer0_
  14. left outer join
  15. jpa_order orders1_
  16. on customer0_.id=orders1_.CUSTOMER_ID
  17. where
  18. customer0_.id=?
  19. Hibernate:
  20. update
  21. jpa_order
  22. set
  23. name=?
  24. where

注意:这时@OneToMany(fetch=FetchType.EAGER)

删除测试

删除测试函数:

  1. @Test
  2. public void testRemove() {
  3. Customer customer = entityManager.find(Customer.class, 4);
  4. entityManager.remove(customer);
  5. }

此时customer表内容记录如下:

order表记录如下:

此时执行删除,可以删除成功,删除后customer.id=4的记录被删除了,而order表中id=5,6记录的customer_id值被置为null。

删除后结果为:

customer表记录:

order表记录:

从执行打印语句可以看出:

  1. Hibernate:
  2. select
  3. customer0_.id as id1_0_0_,
  4. customer0_.age as age2_0_0_,
  5. customer0_.birth as birth3_0_0_,
  6. customer0_.createDate as createDa4_0_0_,
  7. customer0_.FULL_NAME as FULL_NAM5_0_0_,
  8. orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
  9. orders1_.id as id1_1_1_,
  10. orders1_.id as id1_1_2_,
  11. orders1_.name as name2_1_2_
  12. from
  13. jpa_customer customer0_
  14. left outer join
  15. jpa_order orders1_
  16. on customer0_.id=orders1_.CUSTOMER_ID
  17. where
  18. customer0_.id=?
  19. Hibernate:
  20. update
  21. jpa_order
  22. set
  23. CUSTOMER_ID=null
  24. where
  25. CUSTOMER_ID=?
  26. Hibernate:
  27. delete
  28. from
  29. jpa_customer
  30. where
  31. id=?

实际上,我们可以通过配置@OneToMany的级联删除属性,可以通过删除customer来实现级联删除的。

修改Customer.java中的@OneToMany注解信息:

这里修改配置后Customer的getOrders()方法的注解为:

  1. // 映射一对多的关联关系
  2. // @JoinColumn 用来映射一对多的关联关系
  3. // @OneToMany 用来映射外键列
  4. @JoinColumn(name = "CUSTOMER_ID")
  5. @OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.REMOVE)
  6. public Set<Order> getOrders() {
  7. return orders;
  8. }

此时,测试通过删除customer.id=1的记录,测试结果可以成功级联删除,执行打印结果为:

  1. Hibernate:
  2. select
  3. customer0_.id as id1_0_0_,
  4. customer0_.age as age2_0_0_,
  5. customer0_.birth as birth3_0_0_,
  6. customer0_.createDate as createDa4_0_0_,
  7. customer0_.FULL_NAME as FULL_NAM5_0_0_,
  8. orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
  9. orders1_.id as id1_1_1_,
  10. orders1_.id as id1_1_2_,
  11. orders1_.name as name2_1_2_
  12. from
  13. jpa_customer customer0_
  14. left outer join
  15. jpa_order orders1_
  16. on customer0_.id=orders1_.CUSTOMER_ID
  17. where
  18. customer0_.id=?
  19. Hibernate:
  20. update
  21. jpa_order
  22. set
  23. CUSTOMER_ID=null
  24. where
  25. CUSTOMER_ID=?
  26. Hibernate:
  27. delete
  28. from
  29. jpa_order
  30. where
  31. id=?
  32. Hibernate:
  33. delete
  34. from
  35. jpa_order
  36. where
  37. id=?
  38. Hibernate:
  39. delete
  40. from
  41. jpa_customer
  42. where
  43. id=?

JPA(六):映射关联关系------映射单向一对多的关联关系的更多相关文章

  1. 7、单向一对多的关联关系(1的一方有n的一方的集合属性,n的一方却没有1的一方的引用)

    单向一对多的关联关系 具体体现:1的一方有n的一方的集合的引用,n的一方却没有1的一方的引用 举个例子:顾客Customer对订单Order是一个单向一对多的关联关系.Customer一方有对Orde ...

  2. JPA中实现单向一对多的关联关系

    场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...

  3. Hibernate5.2关联关系之单向一对多(一)

    Hibernate5.2之单向一对多 一. 简介    Hibernate中最复杂的应该就是各种关联(单向一对多.单向多对一.双向一对多.一对一.多对多)关系的映射,于是笔者就想着去写一些关于Hibe ...

  4. JPA 单向一对多关联关系

    映射单向一对多的关联关系 1.首先在一的一端加入多的一端的实体类集合 2.使用@OneToMany 来映射一对多的关联关系3.使用@JoinColumn 来映射外键列的名称4.可以使用@OneToMa ...

  5. JPA中实现双向一对多的关联关系

    场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...

  6. JPA(五):映射关联关系------映射单向多对一的关联关系

    映射单向多对一的关联关系 新建Customer.java: package com.dx.jpa.singlemanytoone; import java.util.Date; import java ...

  7. jpa单向一对多关联映射

    如果在一的@OneToMany有@manyToOne则是双向一对多关联,如果在多的那面没有@manyToOne关联则是单向一对多关联 class和student是一对多的关系 表结构 student ...

  8. JPA总结——实体关系映射(一对多@OneToMany)

    JPA总结——实体关系映射(一对多@OneToMany) 注意:本文出自“阿飞”的博客,如果要转载本文章,请与作者联系! 并注明来源: http://blog.sina.com.cn/s/blog_4 ...

  9. JPA 对象关系映射之关联关系映射策略

    关联关系映射 关联关系映射,是映射关系中比较复杂的一种映射关系,总的说来有一对一.一对多和多对多几种关系.细分起来他们又有单向和双向之分.下面我们逐一介绍一下. 回页首 单向 OneToOne 单向一 ...

随机推荐

  1. Wingdings 2 符号编码对照表

     http://blog.csdn.net/linux7985/article/details/5030754 符号  编码 HTML 代码  符号  编码 HTML 代码 ! ! " &q ...

  2. 从PHP客户端看MongoDB通信协议(转)

    MongoDB 的 PHP 客户端有一个 MongoCursor 类,它是用于获取一次查询结果集的句柄(或者叫游标),这个简单的取数据操作,内部实现其实不是那么简单.本文就通过对 MongoCurso ...

  3. Android签名详解

    1.什么是签名?      如果这个问题不是放在Android开发中来问,如果是放在一个普通的版块,我想大家都知道签名的含义.可往往就是将一些生活中常用的术语放在计算机这种专业领域,大家就开始迷惑了. ...

  4. RabbitMQ简单使用

    环境搭建: RabitMQ是用Elang编写的,虽然Elang本身是跨平台的,但也同时意味着搭建Rabit环境需要首先配置Elang环境.配置RabitMQ的网上教程还比较多的: windows 下 ...

  5. 在centos中安装jenkins master为service

    需要sudo或root权限.    翻译自: https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+on+Red+Hat+dis ...

  6. java之jvm学习笔记十三(jvm基本结构) 通俗易懂的JVM 文件,没有之一

    http://blog.csdn.net/yfqnihao/article/details/8289363

  7. Revit API选择三维视图上一点

    start [TransactionAttribute(Autodesk.Revit.Attributes.TransactionMode.Manual)] public class cmdPickP ...

  8. DELPHI 常用虚拟键:VK_

    常数名称                          十六进制值          十进制值     对应按键 VK_LBUTTON                       01       ...

  9. Mybatis配置返回为修改影响条数

    mybatis配置返回为修改影响条数,修改jdbc连接如下即可:添加useAffectedRows=true配置. jdbc:mysql://jdbc.host/{jdbc.db}?useAffect ...

  10. div与span区别及用法

    DIV与SPAN区别及div与san用法篇 接下来了解在div+css开发的时候在html网页制作,特别是标签运用中div和span的区别及用法.新手在使用web标准(div css)开发网页的时候, ...