Persistence

Persistence类使用于获取EntityManagerFactory实例,该类包含一个名为createEntityManagerFactory的静态方法。

        // 创建EntityManagerFactory
String persistenceUnitName = "Jpa-helloword";
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);

Persistence提供了两个创建EntityManagerFactory的方法:

        Map<String, Object> map = new HashMap<>();
map.put("hibernate.show_sql", false);
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName, map);

该方法中可以起到修改persistence.xml的作用。

上边的代码尽管persistence.xml配置内配置项“hibernate.format_sql”属性为true,但是我们在创建EntityManagerFactory的方法中传入了参数后,会覆盖persistence.xml中的配置项的值。

EntityManagerFactory

EntityManagerFactory接口主要用来创建EnittyManager实例,该接口约定了如下4个方法:

  • createEntityManager():用于创建实体管理器对象实例。
  • createEntityManager(Map map):用于创建实体管理器对象实例的重载方法,Map参数用于提供EntityManager的属性。
  • isOpen():检查EntityManagerFactory是否处于打开状态。实体管理器工厂创建后一直处于打开状态,除非调用close()方法将其关闭。
  • close():关闭EntityFactoryFactory。EntityManagerFactory关闭后将释放所有资源,isOpen()方法测试将返回false,其它方法将不能调用,否则将导致IllegalStateException异常。

EntityManager

准备工作:新建功能添加JPA,Spring依赖相关参考《JPA(二):HellWord工程

Person.java

package com.dxsoft.jpa.helloword;

import java.util.Date;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence; import org.junit.After;
import org.junit.Before;
import org.junit.Test; public class Client {
private String persistenceUnitName = "Jpa-helloword";
private EntityManagerFactory entityManagerFactory = null;
private EntityManager entityManager = null;
private EntityTransaction entityTransaction = null; @Before
public void init() {
// 1.创建EntityManagerFactory
entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
// 2.创建EntityManager
entityManager = entityManagerFactory.createEntityManager();
// 3.开始事务
entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
} @After
public void destory() {
// 5.提交事务
entityTransaction.commit(); // 6.关闭EntityManager
entityManager.close();
// 7.关闭EnityManagerFactory
entityManagerFactory.close();
}

测试类:PersonTest.java

package com.dxsoft.jpa.helloword;

import java.util.Date;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence; import org.junit.After;
import org.junit.Before;
import org.junit.Test; public class PersonTest {
private String persistenceUnitName = "Jpa-helloword";
private EntityManagerFactory entityManagerFactory = null;
private EntityManager entityManager = null;
private EntityTransaction entityTransaction = null; @Before
public void init() {
// 1.创建EntityManagerFactory
entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
// 2.创建EntityManager
entityManager = entityManagerFactory.createEntityManager();
// 3.开始事务
entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
} @After
public void destory() {
// 5.提交事务
entityTransaction.commit(); // 6.关闭EntityManager
entityManager.close();
// 7.关闭EnityManagerFactory
entityManagerFactory.close();
}
}

EntityManager#persistence

类似于Hibernate中的save方法,但是不同的是Hibernate允许添加实体对象指定了id,而JPA不允许。

    @Test
public void testPersistence() {
Person person = new Person();
person.setFullName("AA");
person.setAge(20);
person.setBirth(new Date());
person.setCreateTime(new Date());
person.setId(1); entityManager.persist(person);
}

JPA如果指定了id,则抛出异常:

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.dxsoft.jpa.helloword.Person

但不指定id时,则能成功执行:

    @Test
public void testPersistence() {
Person person = new Person();
person.setFullName("AA");
person.setAge(20);
person.setBirth(new Date());
person.setCreateTime(new Date()); entityManager.persist(person);
}

操作日志:

Hibernate:
select
next_val as id_val
from
hibernate_sequence for update Hibernate:
update
hibernate_sequence
set
next_val= ?
where
next_val=?
Hibernate:
insert
into
jpa_person
(age, birth, createTime, full_name, id)
values
(?, ?, ?, ?, ?)

EntityManager#find

类似于Hibernate中的get方法

    @Test
public void testFind() {
Person person = entityManager.find(Person.class, 1);
System.out.println("-------------------------");
System.out.println(person);
}

打印日志:

Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?
-------------------------
Person [id=1, fullName=AA, age=20, birth=2018-06-19, createTime=2018-06-19 20:40:31.0]

备注:从打印信息中可以看出,调用了find方法后立即执行了查询,之后才打印“-------------------------”

EntityManager#getReference

类似于Hibernate中的load方法,懒加载。

    @Test
public void testGetReference() {
Person person = entityManager.getReference(Person.class, 1);
// 从打印信息可以说明返回的对象person是一个代理对象。
System.out.println(person.getClass().getName()); System.out.println("-------------------------"); System.out.println(person);
}

打印信息:

com.dxsoft.jpa.helloword.Person$HibernateProxy$4AN8PTeG
-------------------------
Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?
Person [id=1, fullName=AA, age=20, birth=2018-06-19, createTime=2018-06-19 20:40:31.0]

备注:从打印信息中可以看出,调用了find方法后并未立即执行了查询,而是先执行了打印“-------------------------”,当调用person代理对象时才执行了查询。

需要注意:如果关闭了连接后,再去读取对象则会抛出异常。

    @Test
public void testGetReference() {
Person person = entityManager.getReference(Person.class, 1);
// 从打印信息可以说明返回的对象person是一个代理对象。
System.out.println(person.getClass().getName()); System.out.println("-------------------------"); // 5.提交事务
entityTransaction.commit();
// 6.关闭EntityManager
entityManager.close(); System.out.println(person);
}

抛出异常:

org.hibernate.LazyInitializationException: could not initialize proxy [com.dxsoft.jpa.helloword.Person#1] - no Session

EntityManager#remove

类似Hibernate的delete方法,但是不同之处hibernate允许删除游离和持久化对象。但是JPA只允许删除持久化对象。

JPA删除游离对象会抛出异常:

    @Test
public void testDelete() {
Person person = new Person();
person.setId(1);
entityManager.remove(person);
}

抛出异常:

java.lang.IllegalArgumentException: Removing a detached instance com.dxsoft.jpa.helloword.Person#1

允许删除持久化对象。

    @Test
public void testDelete() {
Person person = entityManager.find(Person.class, 1);
entityManager.remove(person);
}

执行日志:

Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?
Hibernate:
delete
from
jpa_person
where
id=?

EntityManager#merge

merge方法类似于hibernate中的saveOrUpdate方法,但是比hibernate中的saveOrUpdate方法要复杂。

merge(T entity):merge()用于处理Enitty的同步。即数据库的插入和更新操作。

1)如果传入的是一个临时对象,会创建一个新的对象,把临时对象的属性复制到新的对象中,然后对新的对象进行持久化操作。所以新的对象中有id,但临时对象中没有id。

    @Test
public void testMerge1() {
Person person = new Person();
person.setFullName("AA");
person.setAge(20);
person.setBirth(new Date());
person.setCreateTime(new Date()); Person person2 = entityManager.merge(person); System.out.println("person id:" + person.getId());
System.out.println("person2 id:" + person2.getId());
}

执行打印结果:

Hibernate:
select
next_val as id_val
from
hibernate_sequence for update Hibernate:
update
hibernate_sequence
set
next_val= ?
where
next_val=?
person id:null
person2 id:2
Hibernate:
insert
into
jpa_person
(age, birth, createTime, full_name, id)
values
(?, ?, ?, ?, ?)

2)若传入的是一个游离对象(即传入的对象有id),

2.1)如果在EntityManager缓存中没有该对象,

2.2)且在数据中也没有对应的记录,

2.3)则JPA会创建一个新的对象,然后把当前游离对象的属性复制到新创建的对象中,

2.4)对新创建的对象执行insert操作。

    @Test
public void testMerge2() {
Person person = new Person();
person.setFullName("AA");
person.setAge(20);
person.setBirth(new Date());
person.setCreateTime(new Date()); // 此时数据中没有id为100的记录。
person.setId(100); Person person2 = entityManager.merge(person); System.out.println("person id:" + person.getId());
System.out.println("person2 id:" + person2.getId());
}

打印记录:

Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?
Sun Jun 24 18:31:42 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Hibernate:
select
next_val as id_val
from
hibernate_sequence for update Hibernate:
update
hibernate_sequence
set
next_val= ?
where
next_val=?
person id:100
person2 id:3
Hibernate:
insert
into
jpa_person
(age, birth, createTime, full_name, id)
values
(?, ?, ?, ?, ?)

3)若传入的是一个游离对象(即传入的对象有id),

3.1)如果在EntityManager缓存中没有该对象,

3.2)但在数据中有对应的记录,

3.3)则JPA会查询对应的记录,然后返回该记录对应的一个对象,然后把游离对象的属性复制到查询返回对象中。

3.4)对查询返回的对象执行update操作。

    @Test
public void testMerge3() {
Person person = new Person();
person.setFullName("EE");
person.setAge(20);
person.setBirth(new Date());
person.setCreateTime(new Date()); // 此时数据中没有id为100的记录。
person.setId(3); Person person2 = entityManager.merge(person); System.out.println(person2 == person);
}

执行前数据库中数据记录:

执行后数据库中数据记录:

执行打印结果:

Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?
false
Hibernate:
update
jpa_person
set
age=?,
birth=?,
createTime=?,
full_name=?
where
id=?

4)若传入的是一个游离对象(即传入的对象有id),

4.1)如果在EntityManager缓存中有该对象,

4.2)则JPA会把游离对象的属性复制到EntityManager缓存中的对象中。

4.3)EntityManager缓存中的对象执行update操作。

注意:hibernate不允许Session在同一个时刻将两个id相同的对象进行关联,但是JPA允许。

hibernate将抛出异常:

    @Test
public void testMerge4() {
Person person = new Person();
person.setFullName("FF");
person.setAge(20);
person.setBirth(new Date());
person.setCreateTime(new Date()); person.setId(3); Person person2 = entityManager.find(Person.class, 3);
entityManager.merge(person); System.out.println(person2 == person);
}

执行前数据中记录:

执行后数据库中记录:

执行打印记录:

Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?
false
Hibernate:
update
jpa_person
set
age=?,
birth=?,
createTime=?,
full_name=?
where
id=?

EntityManager其他方法

flush():同步持久化上下文环境,即将持久化上下文环境的所有未保存的状态信息保存到数据库中。

setFlushMode(FlushModeType flushMode):设置持久上下文环境的Flush模式。参数可以取两个枚举值:

--- FlushModeType.AUTO:为自动更新数据库实体;

--- FlushModeType.COMMIT:为直接提交事务时才更新数据库记录。

getFlushMode():获取持久上下文环境的Flush模式。返回FlushModeType类的枚举值。

    @Test
public void testFlush() {
Person person = entityManager.find(Person.class, 3);
person.setFullName("Flush Method"); //entityManager.flush();
System.out.println(entityManager.getFlushMode());
System.out.println("---------------------");
}

此时从打印信息可以得知,知道transaction.commit();执行才执行update,

Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?
AUTO
---------------------
Hibernate:
update
jpa_person
set
age=?,
birth=?,
createTime=?,
full_name=?
where
id=?

开启刷新同步持久化上下文环境:

    @Test
public void testFlush() {
Person person = entityManager.find(Person.class, 3);
person.setFullName("Flush_Method"); entityManager.flush();
System.out.println(entityManager.getFlushMode());
System.out.println("---------------------");
}

此时执行信息如下:

Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?
Hibernate:
update
jpa_person
set
age=?,
birth=?,
createTime=?,
full_name=?
where
id=?
AUTO
---------------------

refresh(Object Entity):用数据库实体记录的值更新实体对象的状态,即更新实例的属性值。

clear():清除持久上下文环境,断开所有关联的实体。如果这时还有未提交的更新则会被撤销。

contains(Object entity):判断一个实体是否属于当前持久上下文环境管理的实体。

isOpen():判断当前的实体管理器是否是打开状态。

getTransaction():返回资源层的事务对象。EntityTransaction实例可以用于开始和提交多个事务。

close():关闭实体管理器。之后若调用实体管理器实例的方法或其派生的查询对象的方法都将抛出IlleglastateException异常,除了getTransaction和isOpen方法(返回false)。不过,当与实体管理器关闭的事务处于活动状态时,调用close方法后持久上下文将仍处于被管理状态,直到事务完成。

    @Test
public void testRefresh() {
Person person = entityManager.find(Person.class, 3);
person = entityManager.find(Person.class, 3);
}

此时如果没有开启refresh,则会由于JPA存在与Hibernate相似的一级缓存存在的原因,导致值查询数据库一次,从以下打印信息可以看出:

Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?

打开refresh,测试执行:

    @Test
public void testRefresh() {
Person person = entityManager.find(Person.class, 3);
person = entityManager.find(Person.class, 3); entityManager.refresh(person);
}

此时,打印日志中会两次查询:

Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?
Hibernate:
select
person0_.id as id1_0_0_,
person0_.age as age2_0_0_,
person0_.birth as birth3_0_0_,
person0_.createTime as createTi4_0_0_,
person0_.full_name as full_nam5_0_0_
from
jpa_person person0_
where
person0_.id=?

createQuery(String qlString):创建一个查询对象。

createNamedQuery(String name):根据命名的查询语句块创建查询对象。参数为命名的查询语句。

createNativeQuery(String sqlString):使用标准sql语句创建查询对象。参数为标准sql语句字符串。

createNativeQuery(String sqls,String resultSetMapping):使用标准sql语句创建查询对象,并指定返回结果集Map的名称。

EntityTransaction

EntityTransaction接口用来管理资源层实体管理器的事务操作。通过调用实体管理器的getTransaction方法获得其实力。

begin():用于启动一个事务,此后的多个数据库操作将作为整体被提交或撤销。若这时事务已经开启则会抛出IllegalStateException异常。

commit():用于提交当前事务。即将事务启动以后的所有数据库更新操作持久化值数据中。

rollback():撤销(回滚)当前事务,即撤销事务启动后的所有数据库更新操作,从而不对数据库产生影响。

setRollbackOnly():使当前事务只能被撤销。

getRollbackOnly():查看当前事务是否设置了只能撤销标志。

isActive():查看当前事务是否是活动的。如果返回true则不能调用begin方法,否则将抛出IllegalStateException异常;如果返回false则不能调用commit、rollback、setRollbackOnly及getRollbackOnly方法,否则将抛出IllegalStateException异常。

JPA(四):EntityManager的更多相关文章

  1. JPA中entityManager的CRUD

    private EntityManagerFactory entityManagerFactory; private EntityManager entityManager; private Enti ...

  2. JPA的entityManager的find、getReference、persisit、remove方法的使用

    场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...

  3. JPA的entityManager的find方法与getReference方法的区别

    场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...

  4. Spring Data Jpa (四)注解式查询方法

    详细讲解声明式的查询方法 1 @Query详解 使用命名查询为实体声明查询是一种有效的方法,对于少量查询很有效.一般只需要关心@Query里面的value和nativeQuery的值.使用声明式JPQ ...

  5. jpa

    学习尚硅谷jpa笔记: 所依赖的jar包: 首先在META-INF下创建配置文件,persistence.xml <?xml version="1.0" encoding=& ...

  6. Hibernate+JPA (EntityMange讲解)

    近年来ORM(Object-Relational Mapping)对象关系映射,即实体对象和数据库表的映射)技术市场人声音鼎沸,异常热闹, Sun在充分吸收现有的优秀ORM框架设计思想的基础上,制定了 ...

  7. JPA的泛型DAO设计及使用

    使用如Hibernate或者JPA作为持久化的解决方案时,设计一个泛型的DAO抽象父类可以方便各个实体的通用CRUD操作.由于此时大部分实体DAO的CRUD操作基本一样,采用泛型设计解决这个问题,带来 ...

  8. Hibernate+JPA

    参考链接:http://blog.163.com/hero_213/blog/static/398912142010312024809 近年来ORM(Object-Relational Mapping ...

  9. Hibernate与Jpa的关系(2)

    [转自:http://blog.163.com/hero_213/blog/static/398912142010312024809/ ] 近年来ORM(Object-Relational Mappi ...

  10. JPA(Hibernate)

    JPA 1,JPA:Java Persistence API.JPA通过JDK 5.0注解-关系表的映射关系,并将运行期的实体对象持久化到数据库中.JPA是JavaEE中的标准.JPA标准只提供了一套 ...

随机推荐

  1. 接口开发-基于SpringBoot创建基础框架

    说到接口开发,能想到的开发语言有很多种,像什么Java啊..NET啊.PHP啊.NodeJS啊,太多可以用.为什么选择Java,究其原因,最后只有一个解释,那就是“学Java的人多,人员招聘范围大,有 ...

  2. CAP原则(CAP定理)、BASE理论

    CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性). Availability(可用性).Partition tolerance(分区容错性),三者不可得兼. CA ...

  3. CentOS 7搭建KVM在线管理面板WebVirtMgr

    系统版本:CentOS 7.4 WebVirtMgr版本:master分支的20180720版本,下载链接(链接:https://pan.baidu.com/s/1kl060hPHDGbwJUR_iM ...

  4. CodeSmith 基础用法和例子

    〇.            前言 一.            工具设置 CodeSmith默认是不支持中文的,那么我们必须要先设置使其支持中文显示,保存.并且要能够在生成文件中支持中文. [Tools ...

  5. oracle 删除字段中空格

    update  sales_report set region =  REGEXP_REPLACE(region,  '( ){1,}', '')

  6. swift笔记(二) —— 运算符

    基本运算符 Swift支持大部分的标准C语言的操作符,而且做了一些改进,以帮助开发人员少犯低级错误,比方: 本该使用==的时候,少写了个=, if x == y {-} 写成了 if x = y {- ...

  7. WiX: uninstall older version of the application

    I have installer generated by WiX and I want it to ask: "You have already installed this app. D ...

  8. javascript:常用数组操作

    concat()方法 数组和数组的 粘结: var a=[1,2,3,4]; var b=[5,6,7,8]; var c=a.concat(b); console.log(c); // [1,2,3 ...

  9. 如何让xcode自动检查内存泄露

    在project-setting中找到 “Run Static Analyzer” 键,然后把值修改为“YES”.这样在编码的时候,xcode就可以自动为我们检查内存泄露了. 原图片:http://b ...

  10. 如何快速分析一款ios软件或需求的大流程,然后在业务层实现,不牵扯到界面?

    如何快速分析一款ios软件或需求的大流程,然后在业务层实现,不牵扯到界面?