JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 2
原创播客,如需转载请注明出处。原文地址:http://www.cnblogs.com/crawl/p/7704914.html
-----------------------------------------------------------------------------------------------------------------------------------------------------------
笔记中提供了大量的代码示例,需要说明的是,大部分代码示例都是本人所敲代码并进行测试,不足之处,请大家指正~
本博客中所有言论仅代表博主本人观点,若有疑惑或者需要本系列分享中的资料工具,敬请联系 qingqing_crawl@163.com
-----------------------------------------------------------------------------------------------------------------------------------------------------------
前言:继续介绍 JPA ,这一篇将介绍 JPA 的常用 API,以及在 JPA 中映射关联关系。上一篇讲到 JPA 和 Hibernate 关系密切,尤其是在 API 和映射关联关系上,大家可以参看楼主关于 Hibernate 介绍的博客 Hibernate 学习笔记 - 1 和 Hibernate 学习笔记 - 2 ,与 Hibernate 类似的地方楼主也会特别指出。
四、JPA 的 API
1.Persistence :用于获取 EntiryManagerFactory 的实例
1)常用方法:Persistence.createEntityManagerFactory(persistenceUnitName) 方法
String persistenceUnitName = "jpa-1";
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
2. EntiryManagerFactory :常用方法
1)获取 EntiryManager
//创建 EntityManager,类似于 Hibernate 的 SessionFactory
EntityManager entityManager = entityManagerFactory.createEntityManager();
2)close() 方法,关闭自身,此方法不再演示
3. EntityManager 的常用 API
1)find() 方法,类似于 Hibernate 中的 Session 的 get() 方法,在执行 find 方法时就发送 SQL 语句
//类似于 Hibernate 中 Session 的 get 方法
@Test
public void testFind() {
Customer customer = entityManager.find(Customer.class, 1); System.out.println("----------------------------------------"); System.out.println(customer);
}
打印结果为:查看横线的位置便可证明结论。
Hibernate:
select
customer0_.id as id1_2_0_,
customer0_.age as age2_2_0_,
customer0_.birth as birth3_2_0_,
customer0_.createTime as createTi4_2_0_,
customer0_.email as email5_2_0_,
customer0_.LAST_NAME as LAST_NAM6_2_0_
from
JPA_CUSTOMER customer0_
where
customer0_.id=?
----------------------------------------
Customer [id=1, lastName=AA, email=aa@163.com, age=21, birth=2015-10-22, createTime=2017-10-11 22:39:13.0]
2)getReference() 方法,类似于 Hibernate 的 Session 的 load() 方法
//相当于 Hibernate 中 Session 的 load 方法,若不使用查询的对象则返回一个代理对象,到真正使用时才发送 SQL 语句查询
//可能会发生懒加载异常
@Test
public void testGetReference() {
Customer customer = entityManager.getReference(Customer.class, 1);
System.out.println(customer.getClass().getName()); System.out.println("---------------------------------------"); // transaction.commit();
// entityManager.close(); System.out.println(customer);
}
打印结果为:打印的是一个代理对象,并且横线打印在 SQL 前面。
com.software.jpa.helloworld.Customer_$$_javassist_1
---------------------------------------
Hibernate:
select
customer0_.id as id1_2_0_,
customer0_.age as age2_2_0_,
customer0_.birth as birth3_2_0_,
customer0_.createTime as createTi4_2_0_,
customer0_.email as email5_2_0_,
customer0_.LAST_NAME as LAST_NAM6_2_0_
from
JPA_CUSTOMER customer0_
where
customer0_.id=?
Customer [id=1, lastName=AA, email=aa@163.com, age=21, birth=2015-10-22, createTime=2017-10-11 22:39:13.0]
3)persistence() 方法,类似于 Hibernate 的 save() 方法,与 Hibernate 的 save() 方法不同的是其不能插入一个有 id 属性的对象
//类似于 Hibernate 的 save 方法,使对象由临时状态变为持久化对象
//和 Hibernate 的 save 方法的区别为若有 id 属性,则不会执行插入操作而会抛出异常
@Test
public void testPersistence() {
Customer customer = new Customer();
customer.setLastName("BB");
customer.setEmail("bb@163.com");
customer.setBirth(new Date());
customer.setCreateTime(new Date());
customer.setAge(21); // customer.setId(100); entityManager.persist(customer); System.out.println(customer.getId()); }
4)remove() 方法,类似于 Hibernate 中 Session 的 delete 方法,但是其不能删除 游离化对象(仅有 id),执行 5,6行会抛出异常,因为 5 行的 customer 对象为游离化对象
//类似于 Hibernate Session 的 delete 方法,把对象对应的记录从数据库中删除
//注:该方法只能移出 持久化 对象,而 Hibernate 的 delete 方法可以移除游离对象
@Test
public void testRemove() {
// Customer customer = new Customer();
// customer.setId(2); Customer customer = entityManager.find(Customer.class, 2); entityManager.remove(customer); }
5)merge() 方法,类似于 Hibernate 中 Session 的 saveOrUpdate() 方法
① 传入的是一个临时对象(没有 id):会创建一个新的对象,把临时对象的属性复制到新的对象中,然后对新的对象执行持久化操作,13行执行了 merge() 方法,传入了一个临时对象,返回了一个新的对象,产看 15,16 行的结果可知,新的对象有 id,传入的对象木有id,说明是将新的对象插入了数据库
//1.若传入的是一个临时对象(没有 Id)
//会创建一个新的对象,把临时对象的属性复制到新的对象中,然后对新的对象执行持久化操作
//所以 新的对象中有 id,而之前的临时对象中没有 id
@Test
public void testMerge1() {
Customer customer = new Customer();
customer.setAge(23);
customer.setBirth(new Date());
customer.setCreateTime(new Date());
customer.setEmail("cc@126.com");
customer.setLastName("CC"); Customer customer2 = entityManager.merge(customer); System.out.println("customer's id:" + customer.getId());// null
System.out.println("customer's id:" + customer2.getId());//
}
② 传入的是一个游离对象(有 ID):若在 EntityManager 缓存中没有该对象,在数据库中也没有对应的记录,JPA 会创建一个新的对象,把当前游离对象的属性复制到新的对象中,对新创建的对象执行 insert 操作,楼主的数据库对应的表中并没有 id 为 100 customer,15 行同样返回了一个新的对象,根据返回结果可知 ,确实插入的是新的对象
//2.若传入的是一个游离对象,即传入的对象有 OID
//若在 EntityManager 缓存中没有该对象,在数据库中也没有对应的记录,JPA 会创建一个新的对象,
//把当前游离对象的属性复制到新的对象中,对新创建的对象执行 insert 操作
@Test
public void testMerge2() {
Customer customer = new Customer();
customer.setAge(23);
customer.setBirth(new Date());
customer.setCreateTime(new Date());
customer.setEmail("dd@126.com");
customer.setLastName("DD"); customer.setId(100); Customer customer2 = entityManager.merge(customer); System.out.println("customer's id:" + customer.getId());//
System.out.println("customer's id:" + customer2.getId());//
}
③ 传入的是游离对象,即传入的对象有 OID,缓存中没有,但数据库中有对应的对象:JPA 会查询对应的记录,然后返回该记录对应的对象把当前游离对象的属性复制到查询到的对象中,对查询到的对象执行 update 操作
//3.若传入的是一个游离对象,即传入的对象有 OID
//若在 EntityManager 缓存中没有该对象,在数据库中有对应的记录,JPA 会查询对应的记录,然后返回该记录对应的对象
//把当前游离对象的属性复制到查询到的对象中,对查询到的对象执行 update 操作
@Test
public void testMerge3() {
Customer customer = new Customer();
customer.setAge(23);
customer.setBirth(new Date());
customer.setCreateTime(new Date());
customer.setEmail("ff@126.com");
customer.setLastName("FF"); customer.setId(3); Customer customer2 = entityManager.merge(customer); System.out.println(customer == customer2); //false
}
④ 传入的是游离对象,即传入的对象有 OID,EntityManager 缓存中有对应的对象:JPA 会把当前游离对象的属性复制到查询到的 EntityManager 缓存中的对象,对 EntityManager 缓存中的对象执行 update 操作
//4.若传入的是一个游离对象,即传入的对象有 OID
//若在 EntityManager 缓存中有对应的对象,JPA 会把当前游离对象的属性复制到查询到的 EntityManager 缓存中的对象,
//对 EntityManager 缓存中的对象执行 update 操作
@Test
public void testMerge4() {
Customer customer = new Customer();
customer.setAge(23);
customer.setBirth(new Date());
customer.setCreateTime(new Date());
customer.setEmail("dd@126.com");
customer.setLastName("DD"); customer.setId(3);
Customer customer2 = entityManager.find(Customer.class, 3); entityManager.merge(customer); System.out.println(customer == customer2); //false
}
4.EntityTransaction:JPA 中的事务操作
常用 API: begin() commit() rollback() 代码不再演示
五、JPA 中映射关联关系
1. 映射单向多对一的关联关系:Order : Customer n:1 ,Order 中有 Customer 属性,而 Customer 中没有 Order 属性(单向多对一区别于单向一对多)
1)创建 Order 实体类,标注注解,生成数据表,使用 @ManyToOne 映射多对一的关联关系,使用 @JoinColumn 来标注外键
package com.software.jpa.helloworld; 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.ManyToOne;
import javax.persistence.Table; @Table(name="JPA_ORDERS")
@Entity
public class Order { private Integer id; private String orderName; @GeneratedValue
@Id
public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} @Column(name="ORDER_NAME")
public String getOrderName() {
return orderName;
} public void setOrderName(String orderName) {
this.orderName = orderName;
} private Customer customer; /**
* 映射单项 n-1 的关联关系(Customer 和 Order,Order 中有 Customer 属性,而 Customer 中没有 Order 属性)
* 使用 @ManyToOne 来映射多对一的关联关系
* 使用 @JoinColumn 来映射外键
* 可以使用 @ManyToOne 的 fetch 属性来修改默认的关联属性的加载策略
*/
@JoinColumn(name="CUSTOMER_ID")
48 @ManyToOne(fetch=FetchType.LAZY)
public Customer getCustomer() {
return customer;
} public void setCustomer(Customer customer) {
this.customer = customer;
} }
2)单向多对一的保存(persist):保存多对一时,建议先保存 1 的一端,后保存 n 的一端,这样不会多出额外的 UPDATE 语句
3)获取操作(find):默认情况下使用左外连接的方式来获取 n 的一端的对象和其关联的 1 的一端的对象,可以使用 @ManyToOne 的 fetch 属性来修改默认的关联属性的加载策略
4)删除操作(remove):不能直接删除 1 的一端,因为有外键约束
5)修改操作:
2.映射单向 1-n 的关联关系 Customer :Order 1 : n,Customer 中有 Order 的 Set 集合属性,Order 中没有 Customer的属性
1)在 Customer 中添加 Order 的 Set 集合属性,并映射 1-n 关联关系,重新生成数据表
2)保存操作(persist):总会多出 UPDATE 语句,n 的一端在插入时不会同时插入外键列
3)查询操作(find):默认使用懒加载
4)删除操作(remove):默认情况下,若删除 1 的一端,会先把关联的 n 的一端的外键置空,然后再进行删除,可以通过 @OneToMany 的 cascade 属性修改默认的删除策略(CascadeType.REMOVE 为级联删除)
3.映射双向多对一的关联关系(注:双向多对一 同 双向一对多)
1)实体:Customer 中有 Order 的 Set 集合属性,Order 中有 Customer 的属性,注两个实体映射的外键列必须一致,都为 CUSTOMER_ID
2)保存操作(persist):
4.映射双向一对一的关联关系
1)实体:Manager 和 Department ,一个部门有一个经理,一个经理管一个部门
2)创建 Manager 类和 Department 类,Manager 类中有 Department 的引用,Department 中有 Manager 的引用,由 Department 来维护关联关系(实际上双向 1- 1 双方均可以维护关联关系),使用 @OneToOne 来映射 1-1 关联关系。添加必要注解,生成数据表。
3)保存操作:
4)查询操作:
5.映射双向多对多的关联关系
1)实体:Item 和 Category ,一个类别有多个商品,一个商品对应多个类别。双方都包含对方的 Set 集合。创建实体类,添加对应的注解,生成数据表。
2)保存操作:
3)查询操作:
----------------------------------------------------------------------------------------------------------------
相关链接:
JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 1
JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 3
JPA + SpringData 操作数据库 ---- 深入了解 SpringData
JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 2的更多相关文章
- JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 1
原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7703679.html ------------------------------------ ...
- JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 3
原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7718741.html ------------------------------------ ...
- JPA + SpringData 操作数据库 ---- 深入了解 SpringData
原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7735616.html ------------------------------------ ...
- JPA + SpringData 操作数据库--Helloworld实例
前言:谈起操作数据库,大致可以分为几个阶段:首先是 JDBC 阶段,初学 JDBC 可能会使用原生的 JDBC 的 API,再然后可能会使用数据库连接池,比如:c3p0.dbcp,还有一些第三方工具, ...
- 封装类似thinkphp连贯操作数据库的Db类(简单版)。
<?php header("Content-Type:text/html;charset=utf-8"); /** *php操作mysql的工具类 */ class Db{ ...
- (转)JPA + SpringData
jpa + spring data 约定优于配置 convention over configuration http://www.cnblogs.com/crawl/p/7703679.html 原 ...
- JDBC操作数据库的三种方式比较
JDBC(java Database Connectivity)java数据库连接,是一种用于执行上sql语句的javaAPI,可以为多种关系型数据库提供统一访问接口.我们项目中经常用到的MySQL. ...
- 用SpringBoot+MySql+JPA实现对数据库的增删改查和分页
使用SpringBoot+Mysql+JPA实现对数据库的增删改查和分页 JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述 ...
- Spring_boot简单操作数据库
Spring_boot搭配Spring Data JPA简单操作数据库 spring boot 配置文件可以使用yml文件,默认spring boot 会加载resources目录的下的applica ...
随机推荐
- “.Net 社区大会”(dotnetConf) 2017 Day 1 Keynote: .NET Everywhere
8月份已经发布了.NET Core 2.0, 大会Keynote 一开始花了大量的篇幅回顾.NET Core 2.0的发布,社区的参与度已经非常高.大会的主题是.NET 无处不在: NET Core ...
- Activiti-03-query api
Query API 有两种方式从引擎中查询数据, 查询 API 和本地查询. API方式: List<Task> tasks = taskService.createTaskQuery ...
- 浅谈Linux虚拟内存
我的orangepi内存很少,所以我打算给它弄个虚拟内存 首先建立一个1G的空文件: dd if=/dev/zero of=/home/swapfile bs=64M count=16 格式化为swa ...
- PHP多进程编程pcntl_fork解
其实PHP是支持并发的,只是平时很少使用而已.平时使用最多的应该是使用PHP-FMP调度php进程了吧. 但是,PHP的使用并不局限于做Web,我们完全也可以使用PHP来进行系统工具类的编程,做监控或 ...
- 跨Storyboard调用
在开发中我们会有这种需求从一个故事板跳到另一个故事板 modal UIStoryboard *secondStoryboard = [UIStoryboard storyboardWithName:@ ...
- 利用原生js制做数据管理平台,适合初学者学习
摘要:数据管理平台在当今社会中运用十分广泛,我们在应用过程中,要对数据进行存储,管理,以及删除查询等操作,而我们在实际设计的时候,大牛们大多用到的是JQuery,而小白对jq理解也较困难,为了让大家回 ...
- PHP实现页面静态化
1.通过buffer来实现 需要用file_put_contents ob_get_clean()等内置函数 ob_start (); include "filterpost.htm ...
- ArrayList底层实现原理
ArrayList概述: ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括null在内的所有元素.除了实现列表接口外,此类还提供一些方法来操作内部用来存储列表的数组 ...
- hdu 4123--Bob’s Race(树形DP+RMQ)
题目链接 Problem Description Bob wants to hold a race to encourage people to do sports. He has got troub ...
- JavaWeb(一)Servlet中的ServletConfig与ServletContext
前言 前面我介绍了一下什么是servlet,它的生命周期,执行过程和它的原理.这里我们做一个简单的回顾! 什么是Servlet? servlet 是运行在 Web 服务器中的小型 Java 程序(即: ...