java JPA中的EntityManager是怎样的

40次阅读
没有评论

java JPA 中的 EntityManager 是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

  JPA 即 Java Persistence API,是 Java EE 中针对持久化数据提供的规范。在使用 JPA 中,我们经常会提到 Entity,Entity 就是在内存中短暂存活,在数据库中被持久化了的对象。Entity 和数据库中的表映射,也就是我们常说的 ORM。我们可以持久化一个 Entity,删除一个 Entity 或者通过 Java Persistence Query Language(JPQL) 来查询 Entity。 

  通过注解的方式声明一个 entity 如下: 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

@Entity  

public class Book { 

 

 @Id 

 @GeneratedValue 

 private Long id; 

 

 private String title; 

 private Float price; 

 private String description; 

 private String isbn; 

 private Integer nbOfPage; 

 private Boolean illustrations; 

 

 // Getters, setters 

  Book Entity 和数据库的映射关系如图: 

java JPA 中的 EntityManager 是怎样的 

 
在 JPA 中,所有的 Entity 都是通过 javax.persistence.EntityManager 的 API 来管理和操纵的。当 EntityManager 管理 Entity 时,所有的 Entity 都会有一个唯一标识(这个标识通常是主键列),Entity 的状态将会和数据库同步。当 Entity 脱离 EntityManager 的管理时,Entity 就变成了一个普通的 Java 对象实例,这时它的状态是 detached。 
  当我们用 new 关键字创建一个新 Entity 时,这个 Entity 对象存在于内存中,JPA 对它没有任何了解。只有当 EntityManager 开始管理它时,它的状态才会和数据库同步。当调用了 EntityManager.remove 方法后,它就会从数据库中删除掉,但 Java 对象还会在内存中存在,直到被垃圾回收掉。 

java JPA 中的 EntityManager 是怎样的 

 


  在我们介绍 EntityManager API 之前,我们先来看看 Persistence Context 的概念。一个 Persistence Context 就是针对一个事物中一段时间内一群被管理的 Entity 的集合。多个具有相同唯一标识的 Entity 实例不能存在于同一个 Persistence Context 中。例如,一个 Book 实例的 ID 是 12,此时就不能有第二个 ID 也是 12 的 Book 实例存在于相同的 Persistence Context 中了。只有存在于 Persistence Context 中的 Enitity 才会被 EntityManager 所管理,它们的状态才会反映到数据库中。Persistence Context 可以被看成一个一级缓存,它可以被 EntityManager 当作存放 Entity 的缓存空间。默认情况下,Entity 在 Persistence Context 存活,直到用户的事物结束。 

  每个事物用户都有自己的 Persistence Context,多个 Persistence Context 访问同一个数据库的实例如下图: 

java JPA 中的 EntityManager 是怎样的 

 
我们可以调用 EntityManager.persist() 方法来持久化一个 Entity,也就是向数据库中插入数据。 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

Customer customer = new Customer(Antony ,  Balla ,  tballa@mail.com  

Address address = new Address(Ritherdon Rd ,  London ,  8QE ,  UK  

customer.setAddress(address); 

tx.begin(); 

em.persist(customer); 

em.persist(address); 

tx.commit(); 

  上例中的 Customer 和 Address 是两个普通的 Java 对象,当被 EntityManager 调用了 persist 方法后,两个对象都变成了 EntityManager 所管理的 Entity。当 Transaction 提交后,他们的数据会被插入到数据库中。这里的 Customer 对象是对象关系的持有者,它对应的表结构应当有一个外键来对应 Address 对象。 
  我们注意一下存储两个对象的顺序。即便是将两个对象存储的顺序颠倒一下,也不会造成外键找不到的错误。之前我们已经说过了,Persistence Context 可以被看作一级缓存。在事物被提交之前,所有的数据都是在内存中的,没有对数据库的访问,EntityManager 缓存了数据,当数据准备好后,以底层数据库期待的顺序将数据更新到数据库中。 

  想查找一个 Entity,有两个类似的方法,代码如下: 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

Customer customer = em.find(Customer.class, 1234L) 

if (customer!= null) { 

//  处理对象  

 

try { 

 Customer customer = em.getReference(Customer.class, 1234L) 

//  处理对象  

} catch(EntityNotFoundException ex) { 

// Entity 没有找到  

 
find 方法会根据主键返回一个 Entity,如果主键不存在数据库中,会返回 null。getReference 和 find 方法很类似,但是只是返回一个 Entity 的引用,不会返回其中的数据。它用于那些我们需要一个 Entity 对象和它的主键但不需要具体数据的情况。如例所示,当 Entity 找不到时,会有 EntityNotFoundException 抛出。 

  一个 Entity 可以通过 EntityManager.remove() 被删除,一但 Entity 被删除,它在数据库中也会被删除,并且脱离了 EntityManager 管理 (detached)。此时这个对象不能再和数据库中的数据同步了。 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

tx.begin(); 

em.remove(customer); 

tx.commit(); 

  在之前的所有例子中,和数据库的数据的同步都是发生在事物提交时。所待执行的改变都是需要一个 SQL 语句的执行。例如在下面的代码中,两条 insert 语句会在事物提交时被执行的数据库中。 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

tx.begin(); 

em.persist(customer); 

em.persist(address); 

tx.commit(); 


  大多数情况下,这种和数据库的同步机制能满足我们程序的需要。如果我们想将对 Persistence Context 中数据改变立刻反映到数据库中,可以通过调用 flush 方法实现。或者我们想将数据库中的数据重新同步回 Persistence Context,可以调用 refresh 方法。当应用程序在叫用了 flush 方法后,又调用了 rollback 方法,所有同步到数据库的数据又会都被回滚。 
  这种同步机制很像我们在 sqlplus 中直接执行多个 SQL 语句,当显性调用 flush 方法时,相当于执行我们已经输入的 SQL 语句,但没有提交事务。当 tx.commit 方法调用时,事物才真正的被提交。如果没有调用 flush 方法,则在 tx.commit 方法调用时先执行已经输入的 SQL 语句再提交事务。 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

tx.begin(); 

em.persist(customer); 

em.flush(); 

em.persist(address); 

tx.commit(); 


  上面这个代码例子中,persist 执行的顺序是要被保证的。因为在调用 flush 方法时,变化已经被同步到数据库中了,即 SQL 语句已经被执行了,如果两个 persist 方法顺序颠倒一下,则会出现外键约束的异常。 

  refresh 方法实现的效果可以通过下面的例子显示出来: 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

Customer customer = em.find(Customer.class, 1234L) 

assertEquals(customer.getFirstName(),  Antony  

customer.setFirstName(William  

em.refresh(customer); 

assertEquals(customer.getFirstName(),  Antony  

  contains 方法会返回一个 Boolean 值,用于检测当前 Persistence Context 中是否存在某个 Entity 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

Customer customer = new Customer(Antony ,  Balla ,  tballa@mail.com  

tx.begin(); 

em.persist(customer); 

tx.commit(); 

assertTrue(em.contains(customer)); 

tx.begin(); 

em.remove(customer); 

tx.commit(); 

assertFalse(em.contains(customer)); 

  clear 方法可以清空当前 Persistence Context,是所有的 Entity 都变成 detached 状态。detach 方法则是只将某个 Entity 变成 detached 状态。前面已经说了 detached 的 Entity 不会和数据库中的数据再进行同步了。 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

Customer customer = new Customer(Antony ,  Balla ,  tballa@mail.com  

tx.begin(); 

em.persist(customer); 

tx.commit(); 

assertTrue(em.contains(customer)); 

em.detach(customer); 

assertFalse(em.contains(customer)); 

  如果我们想使一个 detached 的 Entity 重新和数据库中的数据进行同步,可以调用 merge 方法。想象有这样一个场景,我们需要从数据库中取出某个对象,这个对象从持久层传到表现层之前变成了 detached 状态。在表现层中,Entity 的一些数据发生了变化,我们将这个 Entity 传回持久层并让它变成 managed 状态以将变化反映到数据库中。 

Java 代码   java JPA 中的 EntityManager 是怎样的
 

Customer customer = new Customer(Antony ,  Balla ,  tballa@mail.com  

tx.begin(); 

em.persist(customer); 

tx.commit(); 

em.clear(); 

//  设置一个新的值给一个 detached 的 entity 

customer.setFirstName(William  

tx.begin(); 

em.merge(customer); 

tx.commit(); 

 
最后我们通过一张图来表示 EntityManager 对一个 Entity 的生命周期的改变。 


java JPA 中的 EntityManager 是怎样的

关于 java JPA 中的 EntityManager 是怎样的问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注丸趣 TV 行业资讯频道了解更多相关知识。