JPA(六):映射关联关系------映射单向一对多的关联关系
映射单向一对多的关联关系
新建项目项目请参考《JPA(二):HellWord工程》,基于上一章讲解的《JPA(五):映射关联关系------映射单向多对一的关联关系》中的例子进行修改(需要清空数据中的表,因为本例子还是使用customer,order表来测试,但是关联关系发生了变化):
Customer.java
- package com.dx.jpa.singlemanytoone;
- import java.util.Date;
- import java.util.HashSet;
- import java.util.Set;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.GenerationType;
- import javax.persistence.Id;
- import javax.persistence.JoinColumn;
- import javax.persistence.OneToMany;
- import javax.persistence.Table;
- import javax.persistence.Temporal;
- import javax.persistence.TemporalType;
- import javax.persistence.Transient;
- @Entity
- @Table(name = "jpa_customer")
- public class Customer {
- private Integer id;
- private String fullName;
- private Integer age;
- private Date birth;
- private Date createDate;
- private Set<Order> orders = new HashSet<>();
- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- @Column(name = "FULL_NAME", length = 64, nullable = false)
- public String getFullName() {
- return fullName;
- }
- public void setFullName(String fullName) {
- this.fullName = fullName;
- }
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- @Temporal(TemporalType.DATE)
- public Date getBirth() {
- return birth;
- }
- public void setBirth(Date birth) {
- this.birth = birth;
- }
- @Temporal(TemporalType.TIMESTAMP)
- public Date getCreateDate() {
- return createDate;
- }
- public void setCreateDate(Date createDate) {
- this.createDate = createDate;
- }
- // 映射一对多的关联关系
- // @JoinColumn 用来映射一对多的关联关系
- // @OneToMany 用来映射外键列
- @JoinColumn(name = "CUSTOMER_ID")
- @OneToMany()
- public Set<Order> getOrders() {
- return orders;
- }
- public void setOrders(Set<Order> orders) {
- this.orders = orders;
- }
- // 帮助方法,不希望保存到数据库,但是需要动态获取Customer对象的属性。
- @Transient
- public String getCustomerInfo() {
- return "username:" + fullName + ",age:" + age;
- }
- }
注意:这里在Customer.java中添加了一对多的注解@OneToMany:
- // 映射一对多的关联关系
- // @JoinColumn 用来映射一对多的关联关系
- // @OneToMany 用来映射外键列
- @JoinColumn(name = "CUSTOMER_ID")
- @OneToMany()
- public Set<Order> getOrders() {
- return orders;
- }
Order.java
- package com.dx.jpa.singlemanytoone;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.GenerationType;
- import javax.persistence.Id;
- import javax.persistence.Table;
- @Entity
- @Table(name = "jpa_order")
- public class Order {
- private Integer id;
- private String name;
- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- 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;
- }
- }
初始化JPA项目时,创建表语句如下:
- Hibernate:
- create table hibernate_sequence (
- next_val bigint
- ) engine=InnoDB
- Hibernate:
- insert into hibernate_sequence values ( 1 )
- Hibernate:
- insert into hibernate_sequence values ( 1 )
- Hibernate:
- create table jpa_customer (
- id integer not null,
- age integer,
- birth date,
- createDate datetime,
- FULL_NAME varchar(64) not null,
- primary key (id)
- ) engine=InnoDB
- Hibernate:
- create table jpa_order (
- id integer not null,
- name varchar(255),
- CUSTOMER_ID integer,
- primary key (id)
- ) engine=InnoDB
- Hibernate:
- alter table jpa_order
- add constraint FK7glkngwj74nr8h2amofkp1fjd
- foreign key (CUSTOMER_ID)
- references jpa_customer (id)
persistence.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <persistence version="2.0"
- xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
- <persistence-unit name="Jpa-helloword"
- transaction-type="RESOURCE_LOCAL">
- <!-- 配置使用什么 ORM 产品来作为 JPA 的实现 -->
- <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
- <!-- 添加持久化类 -->
- <class>com.dx.jpa.singlemanytoone.Customer</class>
- <class>com.dx.jpa.singlemanytoone.Order</class>
- <properties>
- <!-- 数据库的相关配置 -->
- <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
- <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/jpa" />
- <property name="javax.persistence.jdbc.user" value="root" />
- <property name="javax.persistence.jdbc.password" value="root" />
- <!-- 指定方言
- MySQL org.hibernate.dialect.MySQLDialect
- MySQL with InnoDB org.hibernate.dialect.MySQLInnoDBDialect
- MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect
- MySQL5 org.hibernate.dialect.MySQL5Dialect
- MySQL5 with InnoDB org.hibernate.dialect.MySQL5InnoDBDialect
- -->
- <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
- <property name="hibernate.show_sql" value="true" />
- <property name="hibernate.format_sql" value="true" />
- <!--
- create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。<br>
- create-drop :每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。<br>
- update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。<br>
- validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。 <br>
- -->
- <property name="hibernate.hbm2ddl.auto" value="update" />
- </properties>
- </persistence-unit>
- </persistence>
此时在order表中创建了外键关联关系:
添加测试
添加测试函数:
- @Test
- public void testPersist() {
- Customer customer = new Customer();
- customer.setFullName("AA");
- customer.setAge(26);
- customer.setBirth(new Date());
- customer.setCreateDate(new Date());
- Order order1 = new Order();
- order1.setName("O-AA-01");
- Order order2 = new Order();
- order2.setName("O-AA-02");
- customer.getOrders().add(order1);
- customer.getOrders().add(order2);
- entityManager.persist(customer);
- entityManager.persist(order1);
- entityManager.persist(order2);
- }
此时执行sql如下:
- Hibernate:
- select
- next_val as id_val
- from
- hibernate_sequence for update
- Hibernate:
- update
- hibernate_sequence
- set
- next_val= ?
- where
- next_val=?
- Hibernate:
- select
- next_val as id_val
- from
- hibernate_sequence for update
- Hibernate:
- update
- hibernate_sequence
- set
- next_val= ?
- where
- next_val=?
- Hibernate:
- select
- next_val as id_val
- from
- hibernate_sequence for update
- Hibernate:
- update
- hibernate_sequence
- set
- next_val= ?
- where
- next_val=?
- Hibernate:
- insert
- into
- jpa_customer
- (age, birth, createDate, FULL_NAME, id)
- values
- (?, ?, ?, ?, ?)
- Hibernate:
- insert
- into
- jpa_order
- (name, id)
- values
- (?, ?)
- Hibernate:
- insert
- into
- jpa_order
- (name, id)
- values
- (?, ?)
- Hibernate:
- update
- jpa_order
- set
- CUSTOMER_ID=?
- where
- id=?
- Hibernate:
- update
- jpa_order
- set
- CUSTOMER_ID=?
- where
- id=?
此时并不是因为customer,order保存顺序导致的(即使调换添加先后顺序也会多处update语句),因为多的一端在插入时不会插入外键列,因此一定会多处update语句。
查询测试
添加测试函数:
- @Test
- public void testFind() {
- Customer customer = entityManager.find(Customer.class, 1);
- System.out.println(customer.getFullName());
- System.out.println(customer.getOrders().size());
- }
执行打印结果:
- Hibernate:
- select
- customer0_.id as id1_0_0_,
- customer0_.age as age2_0_0_,
- customer0_.birth as birth3_0_0_,
- customer0_.createDate as createDa4_0_0_,
- customer0_.FULL_NAME as FULL_NAM5_0_0_
- from
- jpa_customer customer0_
- where
- customer0_.id=?
- AA
- Hibernate:
- select
- orders0_.CUSTOMER_ID as CUSTOMER3_1_0_,
- orders0_.id as id1_1_0_,
- orders0_.id as id1_1_1_,
- orders0_.name as name2_1_1_
- from
- jpa_order orders0_
- where
- orders0_.CUSTOMER_ID=?
- 2
从打印结果上可以看出默认采用懒加载的方式,修改Customer.java中的@OneToMany()中的fetch属性为:@OneToMany(fetch=FetchType.EAGER),此时才会出现非懒加载:
此时,再次执行插叙测试函数,执行打印结果如下:
- Hibernate:
- select
- customer0_.id as id1_0_0_,
- customer0_.age as age2_0_0_,
- customer0_.birth as birth3_0_0_,
- customer0_.createDate as createDa4_0_0_,
- customer0_.FULL_NAME as FULL_NAM5_0_0_,
- orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
- orders1_.id as id1_1_1_,
- orders1_.id as id1_1_2_,
- orders1_.name as name2_1_2_
- from
- jpa_customer customer0_
- left outer join
- jpa_order orders1_
- on customer0_.id=orders1_.CUSTOMER_ID
- where
- customer0_.id=?
- AA
- 2
修改测试
修改测试函数:
- @Test
- public void testUpdate() {
- Customer customer = entityManager.find(Customer.class, 1);
- customer.getOrders().iterator().next().setName("O-XX-01");
- }
此时执行打印结果为:
- Hibernate:
- select
- customer0_.id as id1_0_0_,
- customer0_.age as age2_0_0_,
- customer0_.birth as birth3_0_0_,
- customer0_.createDate as createDa4_0_0_,
- customer0_.FULL_NAME as FULL_NAM5_0_0_,
- orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
- orders1_.id as id1_1_1_,
- orders1_.id as id1_1_2_,
- orders1_.name as name2_1_2_
- from
- jpa_customer customer0_
- left outer join
- jpa_order orders1_
- on customer0_.id=orders1_.CUSTOMER_ID
- where
- customer0_.id=?
- Hibernate:
- update
- jpa_order
- set
- name=?
- where
注意:这时@OneToMany(fetch=FetchType.EAGER)
删除测试
删除测试函数:
- @Test
- public void testRemove() {
- Customer customer = entityManager.find(Customer.class, 4);
- entityManager.remove(customer);
- }
此时customer表内容记录如下:
order表记录如下:
此时执行删除,可以删除成功,删除后customer.id=4的记录被删除了,而order表中id=5,6记录的customer_id值被置为null。
删除后结果为:
customer表记录:
order表记录:
从执行打印语句可以看出:
- Hibernate:
- select
- customer0_.id as id1_0_0_,
- customer0_.age as age2_0_0_,
- customer0_.birth as birth3_0_0_,
- customer0_.createDate as createDa4_0_0_,
- customer0_.FULL_NAME as FULL_NAM5_0_0_,
- orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
- orders1_.id as id1_1_1_,
- orders1_.id as id1_1_2_,
- orders1_.name as name2_1_2_
- from
- jpa_customer customer0_
- left outer join
- jpa_order orders1_
- on customer0_.id=orders1_.CUSTOMER_ID
- where
- customer0_.id=?
- Hibernate:
- update
- jpa_order
- set
- CUSTOMER_ID=null
- where
- CUSTOMER_ID=?
- Hibernate:
- delete
- from
- jpa_customer
- where
- id=?
实际上,我们可以通过配置@OneToMany的级联删除属性,可以通过删除customer来实现级联删除的。
修改Customer.java中的@OneToMany注解信息:
这里修改配置后Customer的getOrders()方法的注解为:
- // 映射一对多的关联关系
- // @JoinColumn 用来映射一对多的关联关系
- // @OneToMany 用来映射外键列
- @JoinColumn(name = "CUSTOMER_ID")
- @OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.REMOVE)
- public Set<Order> getOrders() {
- return orders;
- }
此时,测试通过删除customer.id=1的记录,测试结果可以成功级联删除,执行打印结果为:
- Hibernate:
- select
- customer0_.id as id1_0_0_,
- customer0_.age as age2_0_0_,
- customer0_.birth as birth3_0_0_,
- customer0_.createDate as createDa4_0_0_,
- customer0_.FULL_NAME as FULL_NAM5_0_0_,
- orders1_.CUSTOMER_ID as CUSTOMER3_1_1_,
- orders1_.id as id1_1_1_,
- orders1_.id as id1_1_2_,
- orders1_.name as name2_1_2_
- from
- jpa_customer customer0_
- left outer join
- jpa_order orders1_
- on customer0_.id=orders1_.CUSTOMER_ID
- where
- customer0_.id=?
- Hibernate:
- update
- jpa_order
- set
- CUSTOMER_ID=null
- where
- CUSTOMER_ID=?
- Hibernate:
- delete
- from
- jpa_order
- where
- id=?
- Hibernate:
- delete
- from
- jpa_order
- where
- id=?
- Hibernate:
- delete
- from
- jpa_customer
- where
- id=?
JPA(六):映射关联关系------映射单向一对多的关联关系的更多相关文章
- 7、单向一对多的关联关系(1的一方有n的一方的集合属性,n的一方却没有1的一方的引用)
单向一对多的关联关系 具体体现:1的一方有n的一方的集合的引用,n的一方却没有1的一方的引用 举个例子:顾客Customer对订单Order是一个单向一对多的关联关系.Customer一方有对Orde ...
- JPA中实现单向一对多的关联关系
场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...
- Hibernate5.2关联关系之单向一对多(一)
Hibernate5.2之单向一对多 一. 简介 Hibernate中最复杂的应该就是各种关联(单向一对多.单向多对一.双向一对多.一对一.多对多)关系的映射,于是笔者就想着去写一些关于Hibe ...
- JPA 单向一对多关联关系
映射单向一对多的关联关系 1.首先在一的一端加入多的一端的实体类集合 2.使用@OneToMany 来映射一对多的关联关系3.使用@JoinColumn 来映射外键列的名称4.可以使用@OneToMa ...
- JPA中实现双向一对多的关联关系
场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...
- JPA(五):映射关联关系------映射单向多对一的关联关系
映射单向多对一的关联关系 新建Customer.java: package com.dx.jpa.singlemanytoone; import java.util.Date; import java ...
- jpa单向一对多关联映射
如果在一的@OneToMany有@manyToOne则是双向一对多关联,如果在多的那面没有@manyToOne关联则是单向一对多关联 class和student是一对多的关系 表结构 student ...
- JPA总结——实体关系映射(一对多@OneToMany)
JPA总结——实体关系映射(一对多@OneToMany) 注意:本文出自“阿飞”的博客,如果要转载本文章,请与作者联系! 并注明来源: http://blog.sina.com.cn/s/blog_4 ...
- JPA 对象关系映射之关联关系映射策略
关联关系映射 关联关系映射,是映射关系中比较复杂的一种映射关系,总的说来有一对一.一对多和多对多几种关系.细分起来他们又有单向和双向之分.下面我们逐一介绍一下. 回页首 单向 OneToOne 单向一 ...
随机推荐
- Wingdings 2 符号编码对照表
http://blog.csdn.net/linux7985/article/details/5030754 符号 编码 HTML 代码 符号 编码 HTML 代码 ! ! " &q ...
- 从PHP客户端看MongoDB通信协议(转)
MongoDB 的 PHP 客户端有一个 MongoCursor 类,它是用于获取一次查询结果集的句柄(或者叫游标),这个简单的取数据操作,内部实现其实不是那么简单.本文就通过对 MongoCurso ...
- Android签名详解
1.什么是签名? 如果这个问题不是放在Android开发中来问,如果是放在一个普通的版块,我想大家都知道签名的含义.可往往就是将一些生活中常用的术语放在计算机这种专业领域,大家就开始迷惑了. ...
- RabbitMQ简单使用
环境搭建: RabitMQ是用Elang编写的,虽然Elang本身是跨平台的,但也同时意味着搭建Rabit环境需要首先配置Elang环境.配置RabitMQ的网上教程还比较多的: windows 下 ...
- 在centos中安装jenkins master为service
需要sudo或root权限. 翻译自: https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+on+Red+Hat+dis ...
- java之jvm学习笔记十三(jvm基本结构) 通俗易懂的JVM 文件,没有之一
http://blog.csdn.net/yfqnihao/article/details/8289363
- Revit API选择三维视图上一点
start [TransactionAttribute(Autodesk.Revit.Attributes.TransactionMode.Manual)] public class cmdPickP ...
- DELPHI 常用虚拟键:VK_
常数名称 十六进制值 十进制值 对应按键 VK_LBUTTON 01 ...
- Mybatis配置返回为修改影响条数
mybatis配置返回为修改影响条数,修改jdbc连接如下即可:添加useAffectedRows=true配置. jdbc:mysql://jdbc.host/{jdbc.db}?useAffect ...
- div与span区别及用法
DIV与SPAN区别及div与san用法篇 接下来了解在div+css开发的时候在html网页制作,特别是标签运用中div和span的区别及用法.新手在使用web标准(div css)开发网页的时候, ...