框架学习之JPA(四)

JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。

学习视频:尚硅谷框架jpa学习(有兴趣的同学留言邮箱)

使用软件:eclipse

Java版本:jdk8

本节目录

四、JPA_映射关联关系

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

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

3.映射双向多对一的关联关系

4.映射双向一对一的关联关系

5.映射双向多对多的关联关系

四、JPA_映射关联关系

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

创建Order类

package hue.edu.xiong.jpa;

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.ManyToOne;

import javax.persistence.Table;

@Entity

@Table(name="JPA_ORDERS")

public class Order {

@Id

@GeneratedValue(strategy=GenerationType.AUTO)

private Integer id;

@Column(name="ORDER_NAME")

private String orderName;

//映射单向n-1的关联关系

//使用@ManyToIne来映射多对一的关联关系

//使用@JoinColumn来映射外键

    //上课学到的原则,对方永远是一,即多个我对应一个对方,即多对一

@ManyToOne

@JoinColumn(name="CUSTOMER_ID")

private Customer customer;

//get,set略,请自行补充

}

  

保存测试:

@Test

public void testManyToOnePersist() {

Customer customer = new Customer();

customer.setAge(12);

customer.setEmail("937724308@qq.com");

customer.setLastName("xiong");

customer.setBirth(new Date());

customer.setCreatedTime(new Date());

Order order1 = new Order();

order1.setOrderName("O-FF-1");

Order order2 = new Order();

order2.setOrderName("O-FF-2");

//设置关联关系

order1.setCustomer(customer);

order2.setCustomer(customer);

//执行保存操作

entityManager.persist(customer);

entityManager.persist(order1);

entityManager.persist(order2);

}

  

//修改保存顺序

entityManager.persist(order1);

entityManager.persist(order2);

entityManager.persist(customer);

  

l 第一个测试会发现数据库中是三个insert操作

l 第二个测试修改顺序之后发现是三个insert操作,再是两个update操作

l 保存多对一时,建议先保存1的一端,然后保存n的一端这样不会有额外的update语句

获取测试:

//默认情况下使用左外连接方式来获取N的一端的对象和其关联的1的一端的对象

//可使用@ManyToOne的fetch属性来修改默认的关联属性的加载策略

@Test

public void testManyToOneFind() {

Order order = entityManager.find(Order.class, 1);

System.out.println(order.getOrderName());

System.out.println(order.getCustomer().getLastName());

}
------------------------------------------------------
//懒加载模式 //映射单向n-1的关联关系 //使用@ManyToIne来映射多对一的关联关系 //使用@JoinColumn来映射外键 //可使用@ManyToOne的fetch属性来修改默认的关联属性的加载策略 @ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name="CUSTOMER_ID") private Customer customer;

  

删除测试:

//不能直接删除 1 的一端, 因为有外键约束.

@Test

public void testManyToOneRemove(){

// Order order = entityManager.find(Order.class, 1);

// entityManager.remove(order);

Customer customer = entityManager.find(Customer.class, 5);

entityManager.remove(customer);

}

  

修改测试:

//可以修改外键对应的对象的值将"xiong"->"FFF"

@Test

public void testManyToOneUpdate(){

Order order = entityManager.find(Order.class, 2);

order.getCustomer().setLastName("FFF");

}

  

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

修改Order类,把Customer全部注解掉

package hue.edu.xiong.jpa;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

@Entity

@Table(name="JPA_ORDERS")

public class Order {

@Id

@GeneratedValue(strategy=GenerationType.AUTO)

private Integer id;

@Column(name="ORDER_NAME")

private String orderName;

// //映射单向n-1的关联关系

// //使用@ManyToIne来映射多对一的关联关系

// //使用@JoinColumn来映射外键

// //可使用@ManyToOne的fetch属性来修改默认的关联属性的加载策略

// @ManyToOne(fetch=FetchType.LAZY)

// @JoinColumn(name="CUSTOMER_ID")

// private Customer customer;

//get,set略,请自行补充

}

  

修改Customer类,增加Set<Order> orders,并且设置一对多关系

package hue.edu.xiong.jpa;

import java.util.Date;

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;

@Table(name = "JPA_CUSTOMERS")

@Entity

public class Customer {

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private Integer id;

@Column(name = "LAST_NAME")

private String lastName;

private String email;

private Integer age;

@Temporal(TemporalType.DATE)

private Date birth;

@Temporal(TemporalType.TIMESTAMP)

private Date createdTime;

//设置单向1-n关联关系

@OneToMany

@JoinColumn(name="CUSTOMER_ID")

private Set<Order> orders;

}

保存测试:

//单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句.

//因为 n 的一端在插入时不会同时插入外键列.

@Test

public void testOneToManyPersist(){

Customer customer = new Customer();

customer.setAge(18);

customer.setBirth(new Date());

customer.setCreatedTime(new Date());

customer.setEmail("mm@163.com");

customer.setLastName("MM");

Order order1 = new Order();

order1.setOrderName("O-MM-1");

Order order2 = new Order();

order2.setOrderName("O-MM-2");

//建立关联关系

customer.getOrders().add(order1);

customer.getOrders().add(order2);

//执行保存操作

entityManager.persist(customer);

entityManager.persist(order1);

entityManager.persist(order2);

}
  • 单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句.
  • 因为 n 的一端在插入时不会同时插入外键列.

查找测试:

//默认对关联的多的一方使用懒加载的加载策略.

//可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略

@Test

public void testOneToManyFind(){

Customer customer = entityManager.find(Customer.class, 9);

System.out.println(customer.getLastName());

System.out.println(customer.getOrders().size());

}
  • 默认是使用懒加载模式,可以修改为其他策略模式,怎样修改看下面的删除测试第二个表格内容

删除测试:

//默认情况下, 若删除 1 的一端, 则会先把关联的 n 的一端的外键置空, 然后进行删除.

//可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略.

@Test

public void testOneToManyRemove(){

Customer customer = entityManager.find(Customer.class, 8);

entityManager.remove(customer);

}

  

//设置单向1-n关联关系

//使用 @OneToMany 来映射 1-n 的关联关系

//使用 @JoinColumn 来映射外键列的名称

//可以使用 @OneToMany 的 fetch 属性来修改默认的加载策略

//可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略.

@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE})

@JoinColumn(name="CUSTOMER_ID")

private Set<Order> orders;
  • 将外键修改为空之后再删除
  • 将外键全部删除之后再删除

修改测试:

@Test

public void testUpdate(){

Customer customer = entityManager.find(Customer.class, 10);

customer.getOrders().iterator().next().setOrderName("O-XXX-10");

}

  

3.映射双向多对一的关联关系

  • 若是双向 1-n 的关联关系, 执行保存时
  • 若先保存 n 的一端, 再保存 1 的一端, 默认情况下, 会多出 n 条 UPDATE 语句.
  • 若先保存 1 的一端, 则会多出 n 条 UPDATE 语句
  • 在进行双向 1-n 关联关系时, 建议使用 n 的一方来维护关联关系, 而 1 的一方不维护关联系, 这样会有效的减少 SQL 语句.
  • 注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn属性了.
  • 放弃维护关联关系,不使用JoinColumn标签,在@OneToMany 中使用 mappedBy 属性
// @JoinColumn(name="CUSTOMER_ID")

@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy="customer")

自我理解,就是把上面两个关系组合起来,尽量使用多对一的关系,其他都一样

4.映射双向一对一的关联关系

创建两个类Manager,Department

package hue.edu.xiong.jpa;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.FetchType;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.OneToOne;

import javax.persistence.Table;

@Table(name = "JPA_MANAGERS")

@Entity

public class Manager {

@Id

@GeneratedValue

private Integer id;

@Column(name = "MGR_NAME")

private String mgrName;

// 对于不维护关联关系, 没有外键的一方, 使用 @OneToOne 来进行映射, 建议设置 mappedBy=true

@OneToOne(mappedBy = "mgr")

private Department dept;

//get,set略,请自行补充

}

  

package hue.edu.xiong.jpa;

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 = "JPA_DEPARTMENTS")

@Entity

public class Department {

@Id

@GeneratedValue

private Integer id;

@Column(name = "DEPT_NAME")

private String deptName;

// 使用 @OneToOne 来映射 1-1 关联关系。

// 若需要在当前数据表中添加主键则需要使用 @JoinColumn 来进行映射. 注意, 1-1 关联关系, 所以需要添加 unique=true

@JoinColumn(name = "MGR_ID", unique = true)

@OneToOne(fetch = FetchType.LAZY)

private Manager mgr;

//get,set略,请自行补充

}

  

保存测试:

//双向 1-1 的关联关系, 建议先保存不维护关联关系的一方, 即没有外键的一方, 这样不会多出 UPDATE 语句.

@Test

public void testOneToOnePersistence(){

Manager mgr = new Manager();

mgr.setMgrName("M-BB");

Department dept = new Department();

dept.setDeptName("D-BB");

//设置关联关系

mgr.setDept(dept);

dept.setMgr(mgr);

//执行保存操作

entityManager.persist(mgr);

entityManager.persist(dept);

}

  

  • l双向 1-1 的关联关系, 建议先保存不维护关联关系的一方, 即没有外键的一方, 这样不会多出 UPDATE 语句.

查找测试:

//1.默认情况下, 若获取维护关联关系的一方, 则会通过左外连接获取其关联的对象.

//但可以通过 @OntToOne 的 fetch 属性来修改加载策略.

@Test

public void testOneToOneFind(){

Department dept = entityManager.find(Department.class, 1);

System.out.println(dept.getDeptName());

System.out.println(dept.getMgr().getClass().getName());

}

  

//1. 默认情况下, 若获取不维护关联关系的一方, 则也会通过左外连接获取其关联的对象.

//可以通过 @OneToOne 的 fetch 属性来修改加载策略. 但依然会再发送 SQL 语句来初始化其关联的对象

//这说明在不维护关联关系的一方, 不建议修改 fetch 属性.

@Test

public void testOneToOneFind2(){

Manager mgr = entityManager.find(Manager.class, 1);

System.out.println(mgr.getMgrName());

System.out.println(mgr.getDept().getClass().getName());

}

 

5.映射双向多对多的关联关系

创建两个类item和Category

package hue.edu.xiong.jpa;

import java.util.HashSet;

import java.util.Set;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.JoinColumn;

import javax.persistence.JoinTable;

import javax.persistence.ManyToMany;

import javax.persistence.Table;

@Table(name="JPA_ITEMS")

@Entity

public class Item {

@Id

@GeneratedValue

private Integer id;

@Column(name="ITEM_NAME")

private String itemName;

//使用 @ManyToMany 注解来映射多对多关联关系

//使用 @JoinTable 来映射中间表

//1. name 指向中间表的名字

//2. joinColumns 映射当前类所在的表在中间表中的外键

//2.1 name 指定外键列的列名

//2.2 referencedColumnName 指定外键列关联当前表的哪一列

//3. inverseJoinColumns 映射关联的类所在中间表的外键

@JoinTable(name="ITEM_CATEGORY",

joinColumns={@JoinColumn(name="ITEM_ID", referencedColumnName="ID")},

inverseJoinColumns={@JoinColumn(name="CATEGORY_ID", referencedColumnName="ID")})

@ManyToMany

private Set<Category> categories = new HashSet<>();

//get,set略,请自行补充

}

  

package hue.edu.xiong.jpa;

import java.util.HashSet;

import java.util.Set;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.ManyToMany;

import javax.persistence.Table;

@Table(name = "JPA_CATEGORIES")

@Entity

public class Category {

@Id

@GeneratedValue

private Integer id;

@Column(name = "CATEGORY_NAME")

private String categoryName;

@ManyToMany(mappedBy = "categories")

private Set<Item> items = new HashSet<>();

//get,set略,请自行补充,过分了啊,这个颜色一直调整不好

}

  

必须指定中间表

  • 使用 @ManyToMany 注解来映射多对多关联关系
  • 使用 @JoinTable 来映射中间表
    • name 指向中间表的名字
    • joinColumns 映射当前类所在的表在中间表中的外键
      • name 指定外键列的列名
      • referencedColumnName 指定外键列关联当前表的哪一列
    • inverseJoinColumns 映射关联的类所在中间表的外键

典型多对多,一个学生对应多门课程,一门课程对应多个学生,学生加课程决定成绩

保存案例:

//多对多的保存

@Test

public void testManyToManyPersist(){

Item i1 = new Item();

i1.setItemName("i-1");

Item i2 = new Item();

i2.setItemName("i-2");

Category c1 = new Category();

c1.setCategoryName("C-1");

Category c2 = new Category();

c2.setCategoryName("C-2");

//设置关联关系

i1.getCategories().add(c1);

i1.getCategories().add(c2);

i2.getCategories().add(c1);

i2.getCategories().add(c2);

c1.getItems().add(i1);

c1.getItems().add(i2);

c2.getItems().add(i1);

c2.getItems().add(i2);

//执行保存

entityManager.persist(i1);

entityManager.persist(i2);

entityManager.persist(c1);

entityManager.persist(c2);

}

查找案例:

//对于关联的集合对象, 默认使用懒加载的策略.

//使用维护关联关系的一方获取, 还是使用不维护关联关系的一方获取, SQL 语句相同.

@Test

public void testManyToManyFind(){

// Item item = entityManager.find(Item.class, 5);

// System.out.println(item.getItemName());

//

// System.out.println(item.getCategories().size());

Category category = entityManager.find(Category.class, 3);

System.out.println(category.getCategoryName());

System.out.println(category.getItems().size());

}

  

JPA学习(四、JPA_映射关联关系)的更多相关文章

  1. JPA_映射关联关系

    一:单项多对一的关联关系 例如:订单和客户 1.新创建订单类 package com.atguigu.jpa.helloworld; import javax.persistence.Column; ...

  2. Mybatis基础学习(四)—关系映射

    一.模型分析 user和orders user---->orders 一个用户可以创建多个订单,一对多. orders--->user 一个订单只由一个用户创建,一对一.   orders ...

  3. JPA学习笔记(8)——映射一对多关联关系

    一对多关联关系 本文有很多和多对一是一样的,因此不会写得非常具体. 有看不懂的.能够參考JPA学习笔记(7)--映射多对一关联关系 Order实体类 package com.jpa.helloworl ...

  4. JPA学习(五、JPA_二级缓存)

    框架学习之JPA(五) JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中 ...

  5. JPA学习(二、JPA_基本注解)

    框架学习之JPA(二) JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中 ...

  6. [原创]java WEB学习笔记82:Hibernate学习之路---映射 一对多关联关系,配置,CRUD方法测试及注意点

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

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

    双向一对一的关联关系 举例说明:经理Manager和部门Department是双向一对一关联关系.则Manager实体类中有Department实体对象的引用,反之亦然. 其实体属性定义如下: Lis ...

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

    映射单向一对多的关联关系 新建项目项目请参考<JPA(二):HellWord工程>,基于上一章讲解的<JPA(五):映射关联关系------映射单向多对一的关联关系>中的例子进 ...

  9. Scala学习四——映射和数组

    一.本章要点 Scala有十分易用的语言来创建,查询和遍历映射 你需要从可变和不可变的映射中做出选择 默认情况下,你得到的是一个哈希映射,不过你也可以指明要树形映射 你可以很容易地在Scala映射和J ...

随机推荐

  1. java带图形界面的五子棋

    Main: package BlackWhite; import java.awt.BorderLayout; import java.awt.Color; import java.awt.FlowL ...

  2. mysql——触发器——示例

    数据准备: ), d_id ), name ), age ), sex ), homeadd ) ); ,,,'nan','beijing'); ,,,'nv','hunan'); ,,,'nan', ...

  3. Java中集合关键字的区别

    1. ArrayList.Vector和Stack有什么区别? 1.ArrayList的方法和实现基本上和Vector一样,底层都是数组的实现(简:API基本一样) ​   2.Stack继承了Vec ...

  4. 使用rsync在linux(服务端)与windows(客户端)之间同步

    说明: 1.RsyncServer服务端 系统:CentOS 6.8 IP地址:192.168.247.141 2.Rsync客户端 系统:Windows10 实现目的: Rsync客户端同步服务端/ ...

  5. 小记---------手动执行脚本正常执行,使用crontab定时执行时 不执行

    可能出现的原因就是因为crontab不会从用户的/etc/profile文件中读取环境变量,所以就出现 使用定时crontab执行时 无法执行 抛错 所以在使用crontab 定时执行脚本时  在脚本 ...

  6. 洛谷 P5043 树的同构 题解

    题面 本题的难度其实不及紫题的难度.主要是在hash时的处理细节比较繁琐: 首先是树hash的模板: long long treehash(int u,int fa) { ]; ; ; for(int ...

  7. Django查询数据库返回字典dict数据

    个人观点: 个人认为,在Django项目中, 开发团队为了让使用该框架的用户都使用自带的序列化功能,从而让框架中的SQL返回值很不直观,对于直接使用SQL语句的用户很犯难. 解决: from djan ...

  8. [WPF]BringIntoView

    1.在scrollview 中的frameworkelement可以使用 FE.BringIntoView(); 滚动到此控件. 2.该 方法能一个重载 Bottom.BringIntoView(ne ...

  9. [Vue] vue的一些面试题3

    1. vue 组件里的定时器要怎么销毁? 当生命周期销毁后,并没有将组件中的计时器销毁,虽然页面上看不出来,但是如果在控制台打印的话,会发现计时器还在运行,所以要销毁计时器,避免代码一直执行 cons ...

  10. Css布局 响应式布局介绍

    1. 概念: 写一套css样式可以同时适配多个终端,是为解决移动互联网诞生的. 2. 作用: 面对不同的分辨率设备灵活性强,能够快捷解决多设备显示适应问题 3. 原理 媒体查询 ① 外联式媒体查询语法 ...