JPA学习(四、JPA_映射关联关系)
框架学习之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_映射关联关系)的更多相关文章
- JPA_映射关联关系
一:单项多对一的关联关系 例如:订单和客户 1.新创建订单类 package com.atguigu.jpa.helloworld; import javax.persistence.Column; ...
- Mybatis基础学习(四)—关系映射
一.模型分析 user和orders user---->orders 一个用户可以创建多个订单,一对多. orders--->user 一个订单只由一个用户创建,一对一. orders ...
- JPA学习笔记(8)——映射一对多关联关系
一对多关联关系 本文有很多和多对一是一样的,因此不会写得非常具体. 有看不懂的.能够參考JPA学习笔记(7)--映射多对一关联关系 Order实体类 package com.jpa.helloworl ...
- JPA学习(五、JPA_二级缓存)
框架学习之JPA(五) JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中 ...
- JPA学习(二、JPA_基本注解)
框架学习之JPA(二) JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中 ...
- [原创]java WEB学习笔记82:Hibernate学习之路---映射 一对多关联关系,配置,CRUD方法测试及注意点
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- 9、JPA_映射双向一对一的关联关系
双向一对一的关联关系 举例说明:经理Manager和部门Department是双向一对一关联关系.则Manager实体类中有Department实体对象的引用,反之亦然. 其实体属性定义如下: Lis ...
- JPA(六):映射关联关系------映射单向一对多的关联关系
映射单向一对多的关联关系 新建项目项目请参考<JPA(二):HellWord工程>,基于上一章讲解的<JPA(五):映射关联关系------映射单向多对一的关联关系>中的例子进 ...
- Scala学习四——映射和数组
一.本章要点 Scala有十分易用的语言来创建,查询和遍历映射 你需要从可变和不可变的映射中做出选择 默认情况下,你得到的是一个哈希映射,不过你也可以指明要树形映射 你可以很容易地在Scala映射和J ...
随机推荐
- 【神经网络与深度学习】【VS开发】【CUDA开发】VS2013 配置CUDNN V4 DEMO
VS2013 配置CUDNN V4 DEMO 众所周知,当前主流深度学习的实现中调用的底层API都是cudnn,自己做项目需要开发深度学习模块时,也需要调用cudnn库,因此熟悉cudnn库是很有必要 ...
- 【VS开发】Cameralink接口
目录 1 Camera Link接口的三种配置 ▪ Base Camera Link ▪ Medium Camera Link ▪ Full Camera Link 2 Camera Link三种接口 ...
- CentOS7 linux系统多种方式安装ClickHouse数据库
clickhouse是由俄罗斯Yandex公司开发的列式存储数据库,于2016年开源,clickhouse的定位是快速的数据分析,对于处理海量数据的情况性能非常好,在网上也有很多测试的案例,在大数据的 ...
- Hadoop+HBase分布式部署
test 版本选择
- [LeetCode] 223.矩形面积
题目链接: https://leetcode-cn.com/problems/rectangle-area 难度:中等 通过率:41.3% 题目描述: 在 二维 平面上计算出两个 由直线构成的 矩形重 ...
- 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 F. Islands
On the mysterious continent of Tamriel, there is a great empire founded by human. To develope the tr ...
- 3种Redis分布式锁的对比
我们通常使用的synchronized或者Lock都是线程锁,对同一个JVM进程内的多个线程有效.因为锁的本质 是内存中存放一个标记,记录获取锁的线程是谁,这个标记对每个线程都可见.然而我们启动的多个 ...
- node.js使用swig模块
1.安装swig npm install swig --save 2.创建app.js文件 /*应用程序入口文件*/ /*加载express模块*/ var express = require('ex ...
- vue-mixins和vue高阶组件
我们在开发过程中,因为需求的变更,往往会遇见对现有组件的改造和扩展. 那么我们有什么方法对现有组件进行改造和扩展呢? 常见的我们可以使用mixins方式 下面就让我们来看一下怎么使用mixins方式对 ...
- eclipse中web项目tomcat的设置
1. 出现的问题: web开发中(eclipse环境),为本地项目添加tomcat,我们一般都会选择直接添加.在本次开发中突然遇到一个问题:因为项目涉及到文件上传,我利用MultipartFile进 ...