原创播客,如需转载请注明出处。原文地址: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 : nCustomer 中有 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 工程的问题

JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 2的更多相关文章

  1. JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 1

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7703679.html ------------------------------------ ...

  2. JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 3

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7718741.html ------------------------------------ ...

  3. JPA + SpringData 操作数据库 ---- 深入了解 SpringData

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7735616.html ------------------------------------ ...

  4. JPA + SpringData 操作数据库--Helloworld实例

    前言:谈起操作数据库,大致可以分为几个阶段:首先是 JDBC 阶段,初学 JDBC 可能会使用原生的 JDBC 的 API,再然后可能会使用数据库连接池,比如:c3p0.dbcp,还有一些第三方工具, ...

  5. 封装类似thinkphp连贯操作数据库的Db类(简单版)。

    <?php header("Content-Type:text/html;charset=utf-8"); /** *php操作mysql的工具类 */ class Db{ ...

  6. (转)JPA + SpringData

    jpa + spring data 约定优于配置 convention over configuration http://www.cnblogs.com/crawl/p/7703679.html 原 ...

  7. JDBC操作数据库的三种方式比较

    JDBC(java Database Connectivity)java数据库连接,是一种用于执行上sql语句的javaAPI,可以为多种关系型数据库提供统一访问接口.我们项目中经常用到的MySQL. ...

  8. 用SpringBoot+MySql+JPA实现对数据库的增删改查和分页

    使用SpringBoot+Mysql+JPA实现对数据库的增删改查和分页      JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述 ...

  9. Spring_boot简单操作数据库

    Spring_boot搭配Spring Data JPA简单操作数据库 spring boot 配置文件可以使用yml文件,默认spring boot 会加载resources目录的下的applica ...

随机推荐

  1. 201521123096《Java程序设计》第四周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 继承能够动态绑定,运行时能够自动的选择调用方法,十分方便. 2. 书面作业 (1)注释的应用 ...

  2. 201521123103 《Java学习笔记》 第九周学习总结

    一.本周学习总结 1.以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 二.书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前编写 ...

  3. 201521123018 《Java程序设计》第12周学习总结

    1. 本章学习总结 你对于本章知识的学习总结 2. 书面作业 将Student对象(属性:int id, String name,int age,double grade)写入文件student.da ...

  4. MUI如何调取相册的方法

    第一种是HTML方法 <label> <input style="opacity: 0;" type="file" accept=" ...

  5. mshadow的原理--MXNet

    mshadow的原理--MXNet 这文章主要解释了表达式模板的工作原理(也是mshadow的主要原理),文章的前半部分是翻译自exp-template/README.md.我们会解释它为什么会影响编 ...

  6. iOS多线程编程

    废话不多说,直接上干货.先熟悉一下基本知识,然后讲一下常用的两种,NSOperation和GCD. 一.基础概念 进程: 狭义定义:进程是正在运行的程序的实例(an instance of a com ...

  7. vmware三种网络格式

    网络地址转换(NAT) 这种访问模式指的是虚拟机不占用主机所在局域网的ip,通过使用主机的NAT功能访问局域网和互联网,意味着虚拟机可以访问局域网中的其他电脑,但是其他电脑不知道虚拟机的存在. 使用这 ...

  8. 与 Hadoop 对比,如何看待 Spark 技术?

    主要是先看MapReduce模型有什么问题? 第一:需要写很多底层的代码不够高效,第二:所有的事情必须要转化成两个操作Map/Reduce,这本身就很奇怪,也不能解决所有的情况. 其实Spark出现就 ...

  9. ASP.NET Core 认证与授权[1]:初识认证

    在ASP.NET 4.X 中,我们最常用的是Forms认证,它既可以用于局域网环境,也可用于互联网环境,有着非常广泛的使用.但是它很难进行扩展,更无法与第三方认证集成,因此,在 ASP.NET Cor ...

  10. TomCat系统架构

    1.TomCat总体结构 TomCat有两大核心组件:Connector和Container.Connector组件是可以被替换的,一个Container可以对应多个Connector. 多个Conn ...