实体状态和转换

JPA提供一个持久化上下文作为一级缓存,提供自动脏检查.对应某个id的实例在持久化上下文中只有一个对象.
查询时总是尝试在当前上下文中先搜索对象,不存在再触发数据库查询.
托管状态的bean会建立一个和缓存数据的联系,这时bean的属性改变同时会修改缓存数据,此时这条数据就变成了脏数据。

实体状态详解
临时状态:
 实际上就是new了一个普通的JavaBean对象。
托管状态
 临时状态实体在调用persist()后,会根据策略分配ID,然后会被持久化到数据库中,同时也会在缓存中生成一条数据,即将一般的JavaBean变为了托管状态的Bean,该Bean的任何属性改动都会修改缓存状态,让缓存数据和数据库数据有差异,这时这条数据就变为了脏数据,当进行flush时,就会产生更新数据库操作。
 一旦该记录flush到数据库之后,并且事务提交了,那么此对象不在持久化上下文中,即:变为了游离(没人管的孩子)状态了。
在游离状态的时候调用更新、刷新方法后,游离状态对象就变为了在持久化上下文的托管状态了。
 通过管理器的find方法,将实体从数据库查询出来后,该实体也就变为了托管形态。
持久化状态
 当处在托管状态的实体Bean被管理器flush了,那么就在极短暂的时间进入了持久化状态,事务提交之后,立刻变为了游离状态。
 您可以把持久化状态当做实实在在的数据库记录。
游离状态
 游离状态就是提交到数据库后,事务commit后实体的状态,因为事务已经提交了,此时实体的属性任你如何改变,也不会同步到数据库,因为游离是没人管的孩子,不在持久化上下文中。
销毁对象
 一般要删除一个持久化对象的时候都是先find出来,之后调用remove方法删之,此时这个对象就是销毁对象,实际上就是瞬时对象的另一种形态罢了。

EntityManager一些常用的API

SELECT

find() 和 getReference()
Person person = em.find(Person.class,1);
Person person = em. getReference (Person.class,1);
 异同:
1.当在数据库中没有找到记录时,find()方法会返回null,
而getReference() 方法会抛出javax.persistence.EntityNotFoundException异常,
2.调用getReference()方法,返回的其实并不是实例对象,而是一个代理。当你要使用实体时,才会真正的调用查询语句来查询实例对象
3.另外getReference()方法不保证 entity Bean已被初始化。
4.如果传递进getReference()或find()方法的参数不是实体Bean,都会引发 IllegalArgumentException

INSERT

persist()
 将临时状态的实体持久化到数据库
Person person = new Person();
person.setName(name);
//把数据保存进数据库中
em.persist(person);
persist方法:使对象由临时状态变为持久化状态,就是执行INSERT操作。
1.如果传递进persist()方法的参数不是实体Bean,会引发IllegalArgumentException
2.和hibernate的save()方法有些不同:如果对象有id,则不能执行insert操作,会抛出异常
Merge()
 详见下方

UPDATE

 当实体正在被容器管理,即托管状态,你可以调用实体的set方法对数据进行修改,在容器决定flush时(这个由Container自行判断),更新的数据 才会同步到数据库,而不是在调用了set方法对数据进行修改后马上同步到数据库。如果你希望修改后的数据马上同步到数据库,你可以调用EntityManager.flush()方法。
public void updatePerson() {
Person person = em.find(Person.class, 1);
person.setName(“lihuoming”);
}

Merge
1. 传入的对象没有id
在这种情况下,调用merge方法,将返回一个新的对象(有id),并对这个新的对象执行insert操作。
2. 传入的对象有id,entityManager的缓存中没有该对象,数据库中没有该记录:
在这种情况下,调用merge方法,将返回一个新的对象,并对该对象执行insert操作。
新对象的id是数据库中这条记录的id(比如自增长的id),而不是我们自己传入的id。(其实和情况1的结果是一样的)
3. 传入的对象有id,entityManager的缓存没有该对象,数据库中有该记录
在这种情况下,调用merge方法,将会从数据库中查询对应的记录,生成新的对象,然后将我们传入的对象复制到新的对象,最后执行update操作。
简单来说,就是更新操作。
4. 传入的对象有id,entityManager的缓存有该对象
在这种情况下,调用merge方法,JPA会把传入的对象赋值到entityManager的缓存中的对象,然后对entityManager缓存中的对象执行update操作。
(和情况3的结果一样)
总结:执行merge时,如果实体ID为空,则进行insert操作
如果有ID则进行update操作。

DELETE

Remove()
Person person = em.find(Person.class, 2);
1. 如果级联关系cascade=CascadeType.ALL,在删除person 时候,也会把级联对象删除。把cascade属性设为cascade=CascadeType.REMOVE 有同样的效果。
em.remove (person);
2.如果传递进remove ()方法的参数不是实体Bean,会引发一个IllegalArgumentException
remove()方法不能移除游离对象,只能移除持久化对象
Order order = new Order();
order.setId(140);
entityManager.remove(order);
上面这段代码会抛出异常,因为order是我们自己创建的对象,也就是游离对象。必须这样写:
Order order = new Order();
order = entityManager.find(Order.class, 140);
entityManager.remove(order);
这段代码中的order是从数据库中获取的,也就是持久化对象
hibernate的delete()方法,只要对象有Id,就可以删除

JPQL – createQuery()

SELECT

getResultList()
除了使用find()或getReference()方法来获得Entity Bean之外,你还可以通过JPQL得到实体Bean。
要执行JPQL语句,你必须通过EntityManager的createQuery()或createNamedQuery()方法创建一个Query 对象

Query query = em.createQuery("select p from Person p");
List<Map<String,Object>> result = query.getResultList();

createNamedQuery是命名查询,需要@NamedQuery配合在实体中创建明明查询。

getSingleResult()
返回查询的第一条数据,可以进行强转,如:
查询数目:

Query query = em.createQuery("select count(1) from Person p");
Long num = (Long)query. getSingleResult ();

强转为实体:

Query query = em.createQuery("select p from Person p");
User user = (User)query. getSingleResult ();

executeUpdate()
执行更新和删除操作,返回受影响的记录数。
Query query = em.createQuery(“delete from Person”);
int result = query.executeUpdate(); //影响的记录数
JPQL没有插入语句即不能执行insert语句。

关于JPQL参数问题
1. 使用标识符
Query query = em.createQuery(“delete from Person p where p.id := id”);
query.setParameter(“name”, “张三”);
int result = query.executeUpdate(); //影响的记录数

  1. 使用索引下标
    Query query = em.createQuery(“delete from Person p where p.id = ?1 “);
    query.setParameter(1, “张三”);
    int result = query.executeUpdate(); //影响的记录数

SQL – createNaiveQuery()

用法基本同createQuery(),只不过这里使用的不是JPQL而是SQL

将查询到的数据映射成实体:
Query query = em.createNativeQuery(“select * from person”, Person.class);
List result = query.getResultList();
if (result!=null){
Iterator iterator = result.iterator();
while( iterator.hasNext() ){
Person person= (Person)iterator.next();
… ..
}
}

———————————— SQL END ———————————————————-

EntityManage一些不常用的方法

refresh()
User user = em.find(User.class, 1);
//第二次同样的查询不会访问数据库
user = em.find(User.class, 1);
运行以上代码,发现调用了两次find,但是只执行了一次select语句,这是缓存导致的。
执行refresh()方法刷新缓存,容器会把数据库中的新值重写进实体。
User user = em.find(User.class, 1);
em.refresh(user);
contains()
判断实体是否还在EntityManage的管理下,或者说是否属于当前持久上下文环境。
contains()方法使用一个实体作为参数,如果这个实体对象当前正被持久化内容管理,返回值为true,否则为false。
如果传递的参数不是实体 Bean,将会引发一个IllegalArgumentException.
User user = em.find(User.class, 1);
if (em.contains(user)){
//正在被持久化内容管理
}else{
//已经不受持久化内容管理
}

clear()
1.清除持久上下文环境,断开所有关联的实体。如果这时还有未提交的更新则会被撤消。
2.在处理大量实体的时候,如果你不把已经处理过的实体从EntityManager中分离出来,将会消耗你大量的内存。
3.调用EntityManager 的clear()方法后,所有正在被管理的实体将会从持久化内容中分离出来。
4.有一点需要说明下,在事务没有提交前(事务默认在调用堆栈的最后提交,如:方 法的返回),如果调用clear()方法,之前对实体所作的任何改变将会丢失,
所以建议你在调用clear()方法之前先调用flush()方法保存更改。

flush()
1. ORM框架执行的一些更新数据库的方法,其实质是在更新缓存,只有调用了flush()后才会将缓存同步到数据库,即真正执行SQL语句,但是这时并没有真正将数据保存进数据库,需要事务commit后才能全部保存。
2. 一般flush后立刻就会进行事务的提交。
3. 当EntityManager对象在一个session bean 中使用时,它是和服务器的事务上下文绑定的。
4.在一个session bean 中,服务器的事务默认地会在调用堆栈的最后提交(如:方法的返回)。

setFlushMode()
 改变实体管理器的Flush模式
 setFlushMode()的Flush模式有2种类型:AUTO and COMMIT。AUTO为缺省模式。你可以改变他的值,如下:
em.setFlushMode(FlushModeType.COMMIT);
1. FlushModeType.AUTO:
默认情况下除了在事务提交时flush,在进行查询时(除了find()和getreference()查询)也会进行一次flush,比如使用JPQL查询前会进行一次flush。
使用场合:在 大量更新数据的过程中没有任何查询语句(除了find()和getreference()查询)的执行。
2. FlushModeType.COMMIT:
刷新只有在事务提交时才发生,查询不触发。
使用场合:在大量更新数据的过程中存在查询语句(除了find()和 getreference()查询)的执行。
 其实上面两种模式最终反映的结果是:JDBC 驱动跟数据库交互的次数。
JDBC 性能最大的增进是减少JDBC 驱动与数据库之间的网络通讯。
FlushModeType.COMMIT模式使更新只在一次的网络交互中完成,而FlushModeType.AUTO 模式可能需要多次交互(触发了多少次Flush 就产生了多少次网络交互

isOpen ()
 判断当前的实体管理器是否是打开状态
 getTransaction ()
 返回资源层的事务对象。EntityTransaction实例可以用于开始和提交多个事务

 大量数据分批提交
有的时候我们需要循环保存数据,当保存大量数据的时候,
如果到最后才提交所有数据,那么数据库的负载可能会比较大。我们可以这样做,每30个记录就提交(flush)一次。
代码如下(每到30条记录的时候就强制提交):
public void updateBatch(List list) {
for (int i = 0; i < list.size(); i++) {
entityManager.merge(list.get(i)); //变成托管状态
if (i % 30 == 0) {
entityManager.flush(); //变成持久化状态
entityManager.clear(); //变成游离状态
}
}
}
public void saveBatch(List list) {
for (int i = 0; i < list.size(); i++) {
entityManager.persist(list.get(i)); //变成托管状态
if (i % 30 == 0) {
entityManager.flush(); //变成持久化状态
entityManager.clear(); //变成游离状态
}
}
}

JPA学习 —— 第五课、JPA常用API详解相关推荐

  1. Unity常用API详解--初学必备

    初学Unity3D编程,为了更加熟悉Unity常用API,根据搜集资料整理如下: 1.事件函数执行机制 2.Time类 Time.deltaTime:每一帧的时间. Time.fixedDeltaTi ...

  2. Java程序员从笨鸟到菜鸟之(五十二)细谈Hibernate(三)Hibernate常用API详解及源码分析--csdn 曹胜欢...

    新接触一个框架的目的就是想利用这个框架来为我们做一些工作,或者是让他来简化我们的工作,利用这个框架无非就是要利用这个框架所给我们提供的API去操作我们的数据,所以利用一个框架的好坏很大一部分取决于你对 ...

  3. 【SignalR学习系列】7. SignalR Hubs Api 详解(JavaScript 客户端)

    SignalR 的 generated proxy 服务端 public class ContosoChatHub : Hub {public void NewContosoChatMessage(s ...

  4. opencv学习笔记五:cv2.warpAffine()函数详解

    cv2.warpAffine()函数主要是利用变换矩阵M对图像进行如旋转.仿射.平移等变换,只需要我们提供一个2*3的变换矩阵M,就可以对图像进行变换.它一般是和cv2.getRotationMatr ...

  5. ext核心API详解

    http://hi.baidu.com/j2me/profile 1 EXT核心API详解(一)-Ext 1 EXT核心API详解(二)-Array/Date/Function/Number/Stri ...

  6. Emojify - v2 吴恩达老师深度学习第五课第二周编程作业2

    吴恩达老师深度学习第五课第二周编程作业2,包含答案! Emojify! Welcome to the second assignment of Week 2. You are going to use ...

  7. Spring data JPA 之 Jackson 在实体里面的注解详解

    8 Spring data JPA 之 Jackson 在实体里面的注解详解 经过前⾯课时的讲解,相信你已经对实体⾥⾯的 JPA 注解有了⼀定的了解,但是实际⼯作中你会发现实体⾥⾯不仅有 JPA 的注 ...

  8. Elastic stack技术栈学习(十)— springboot集成ES API详解

    目录 一.关于索引的API详解 1.1 声明客户端 1.2 创建索引 1.3 获取文档 / 判断文档是否存在 ​1.4 删除索引 二.关于文档的API详解 2.1 添加文档 2.2 判断文档是否存在 ...

  9. 第10课:底实战详解使用Java开发Spark程序学习笔记

    第10课:底实战详解使用Java开发Spark程序学习笔记 本期内容: 1. 为什么要使用Java? 2. 使用Java开发Spark实战 3. 使用Java开发Spark的Local和Cluster ...

最新文章

  1. 【只需三步】用IDEA打开一个新的jsp项目如何跑起来(运行起来)
  2. 第三次Scream冲刺
  3. EOS 共识机制 (5)超级节点投票
  4. YbtOJ#20235-[冲刺NOIP2020模拟赛Day9]公共序列【dp】
  5. 基于物理的渲染-用真实的环境光照亮物体
  6. 15行代码抓取兰亭序全文单字高清字帖
  7. Memcached:高性能的分布式内存缓存服务器
  8. config parser 模块
  9. git rebase -i之我见
  10. 【JAVA】jacob写word
  11. VMware8虚拟机安装教程
  12. Linux内核同步机制之(八):mutex
  13. win10系统安装到服务器失败,win10安装失败怎么办?
  14. AUTOSAR MCAL SPI配置
  15. 降低Java垃圾回收开销的5条建议
  16. 教资有小学计算机吗,小学有没有信息技术教师资格证考试?
  17. 09驾校科目一考试系统——提交分数
  18. 习题 6.12 有一行电文,已按下面规律译成密码:...即第1个字母变成第26个字母,第i个字母变成第(26-i+1)个字母,非字母字符不变。要求编程序将密码译回原文,并输出密码和原文。
  19. Git之多人协同开发
  20. horizon服务主要模块_horizon_

热门文章

  1. 数据仓库系列(一)什么是维度建模以及维度建模的基本要素
  2. P6617 查找 Search (线段树)
  3. 记一次失败的《将视频中的音频转换成文字》的经历
  4. 使用NeRF进行3D体素渲染
  5. 卡片式设计流行的秘密 — 看完这15个案例你就懂了!
  6. git branch 相关命令
  7. 开启Fluter基础之旅三-------Material Design风格组件、Cupertino风格组件、Flutter页面布局篇...
  8. css学习笔记-盒子的样式
  9. logstash日志收集走过的坑
  10. 当AI降临教育——阳光还是风暴?