原创播客,如需转载请注明出处。原文地址: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. 201521123012 《Java程序设计》第二周学习总结

    1. 本章学习总结 1.Java中String和StringBuilder的区别. 2.Arrays()的用法. 2.课后作业 1.使用Eclipse关联jdk源代码(截图),并查看String对象的 ...

  2. ZIP格式

    总体格式 分文件头+文件压缩数据 中心目录+中心目录记录结束符 1.分文件头信息 0X 50 4b 03 04 分文件头信息标志,一般是zip文件的开头,可以通过这个判断文件格式 14 00 解压缩所 ...

  3. 基于socket.io的实时在线选座系统

    基于socket.io的实时在线选座系统(demo) 前言 前段时间公司做一个关于剧院的项目,遇到了这样一种情况. 在高并发多用户同时选座的情况下,假设A用户进入选座页面,正在选择座位,此时还没有提交 ...

  4. python之---进程

    一.进程 1.什么是进程 (1)正在进行的一个过程或者说一个任务,而负责执行的就是CPU 2.进程与程序的区别 (1)程序仅仅是一堆代码而已,而进程指的是程序的运行过程 同一个程序执行两次,也是两个进 ...

  5. vim格式化代码

    在命令模式下,按键盘gg=G 命令含义: gg:到达文件头=:缩进G:直到文件尾

  6. 【轉】JS,Jquery获取各种屏幕的宽度和高度

    Javascript: 网页可见区域宽: document.body.clientWidth网页可见区域高: document.body.clientHeight网页可见区域宽: document.b ...

  7. ssl协议以及生成

    一.https协议https是一安全为目标的httpt通道,简单讲师http的安全版.即http下加入ssl层,https的安全基础是ssl,因此加密的详细内容就需要ssl.http和https的区别 ...

  8. xml解析案例

    步骤:Channel是java bean类 public static List<Channel> parsexml(InputStream inputStream) {//注意服务器种是 ...

  9. 西邮linux兴趣小组2014纳新免试题(四)

    [第四关] 题目 http://findakey.sinaapp.com/ Example: String1:FFFF8 5080D D0807 9CBFC E4A04 24BC6 6C840 49B ...

  10. Hibernate中的实体映射

     一.一对一映射  如人(Person)与身份证(IdCard) 的关系,即为一对一的关系,一个人只能有一张身份证,一张身份证只能属于某一个人,它们的关系图如下图所示: 在Person实体中添加一个属 ...