`

Java EE 学习笔记 - JPA Entity的生命周期

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

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

@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和数据库的映射关系如图:



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



 
  在我们介绍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访问同一个数据库的实例如下图:




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

    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,有两个类似的方法,代码如下:


    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)。此时这个对象不能再和数据库中的数据同步了。


    tx.begin();
    em.remove(customer);
    tx.commit();



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

    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语句再提交事务。


    tx.begin();
    em.persist(customer);
    em.flush();
    em.persist(address);
    tx.commit();

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

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

    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

   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不会和数据库中的数据再进行同步了。

    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状态以将变化反映到数据库中。

    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的生命周期的改变。
  • 大小: 415.6 KB
  • 大小: 82.9 KB
  • 大小: 136.1 KB
  • 大小: 174.5 KB
分享到:
评论

相关推荐

    JAVA-EE-master (4).zip

    这个"JAVA-EE-master (4).zip"文件显然包含了与Java EE相关的学习资料、项目源码和教程,旨在帮助开发者提升在Java EE领域的技能。 Java EE作为一个服务器端的应用程序开发平台,它构建在Java SE的基础上,提供了...

    Java EE 超级核心技术笔记与代码

    通过“Java EE 超级核心技术笔记与代码”,读者不仅可以学习理论知识,还能通过实际的代码示例掌握如何在项目中应用这些技术。这将有助于提升开发者在Java EE领域的实践能力,实现“授人以渔”的效果。

    j2ee.rar_java 学习笔记

    Java EE容器(如应用服务器)为组件提供生命周期管理和资源注入,如事务管理、安全性、依赖注入等,让开发者专注于业务逻辑。 **总结** 这份J2EE学习笔记涵盖了Java EE开发的基本要素,从基础的Servlet和JSP到高级...

    javaee思维导图版笔记-吉林大学

    "javaee思维导图版笔记-吉林大学" 本笔记主要涵盖了Java EE的基础知识,包括Servlet、JSP、JNDI、JPA等方面的内容。 ...本笔记可以作为Java EE学习的参考资料,帮助读者更好地理解Java EE技术栈。

    j2ee笔记--很有用的东西

    10. **CDI(Contexts and Dependency Injection)**:CDI提供了一种管理对象生命周期和依赖关系的方式,简化了Java EE应用的组件管理和注入。 这份"j2ee笔记"可能详细解释了这些概念,给出了实例代码和面试常见问题...

    java web 笔记整理

    Servlet生命周期包括加载、初始化、服务、销毁四个阶段。通过Override `service()` 方法来处理请求,使用`doGet()`和`doPost()`处理GET和POST请求。 2. **JSP(JavaServer Pages)**:JSP是一种视图技术,允许将...

    EJB概述 学习笔记

    EJB容器是运行EJB组件的环境,负责管理bean的生命周期、事务、安全性、并发控制以及资源管理。容器提供了许多服务,如: - **事务管理**:支持不同级别的事务隔离和恢复机制。 - **安全性**:提供角色基的安全...

    EJB学习笔记

    Enterprise JavaBeans(EJB)是Java EE平台的核心组件之一,用于构建可扩展、安全和事务性的企业级应用程序。本学习笔记将深入探讨EJB的概念、架构、类型以及如何在实际项目中应用它们。 EJB是一种服务器端的组件...

    EJB学习笔记.rar

    5. **生命周期管理**:EJB容器负责Bean的创建、初始化、激活、钝化、销毁等过程,开发者只需关注业务逻辑。 6. **资源注入**:通过依赖注入(Dependency Injection,DI)机制,EJB可以从容器中自动获取所需的资源,...

    Hibernate学习笔记

    - `persistence.xml`(JPA环境):在Java EE环境中,用于定义实体类和数据源。 ### 四、对象关系映射(ORM) ORM是Hibernate的核心功能,它将Java对象映射到数据库表。通过注解或XML映射文件,我们可以定义对象...

    达内培训的ejb课程笔记

    2. **实体bean(Entity Beans)**:映射到数据库中的持久化对象,用来管理业务对象的生命周期。实体bean有两种形式:传统实体bean(EJB 2.x)和Java Persistence API(JPA)中的实体bean(EJB 3.x及更高版本)。 3....

    ejb3.0_培训笔记(达内).

    4. **依赖注入(Dependency Injection)**:EJB 3.0引入了JSR 250规范,提供了依赖注入功能,允许容器自动管理Bean的生命周期和依赖关系。通过`@Inject`和`@EJB`注解,可以方便地注入其他Bean或资源,减少了代码的...

    java EJB资料

    - 提供的教程如“EJB学习笔记.docx”、“精通EJB3.0.pdf”等,通常涵盖了EJB的基本概念、组件使用、部署配置以及最佳实践。 9. **源码分析**: - “EJB3.0实例教程(含源码).rar”提供了实际项目源码,帮助读者...

    j2ee超级核心技术笔记与代码

    Servlet生命周期包括加载、实例化、初始化、服务、销毁五个阶段。 2. JSP(JavaServer Pages):JSP是HTML与Java代码结合的视图层技术,简化了动态内容的创建。JSP文件在服务器上被编译成Servlet执行,实现视图与...

    学习EJB3基础知识笔记

    包括资源管理、并发控制、生命周期管理、远程接口支持等,开发者可以专注于业务逻辑,而不必关心底层实现。 9. **EjbDemo**: 这个压缩包可能包含了一个EJB3的示例项目,其中可能包括了Bean的源代码、配置文件...

    软件工程师下午考试笔记

    考生需要理解它们的生命周期、转发与包含的区别,以及如何在JSP中使用EL(表达式语言)和JSTL(JavaServer Pages Standard Tag Library)。 7. **Struts**: Struts是一个基于MVC设计模式的Java Web框架,它简化了...

    MLDN_J2EE框架_笔记

    9. **CDI(Contexts and Dependency Injection)**:CDI是Java EE中的一种依赖注入框架,简化了组件间的依赖管理和生命周期管理。 10. **WS(Web Services)**:通过SOAP(Simple Object Access Protocol)和WSDL...

Global site tag (gtag.js) - Google Analytics