JPA是啥?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JPA是啥?相关的知识,希望对你有一定的参考价值。

JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据。它的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate、TopLink,JDO等ORM框架各自为营的局面。值得注意的是,JPA是在充分吸收了现有Hibernate、TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用、伸缩性强等优点。从目前的开发社区的反应上看,JPA受到了极大的支持和赞扬,其中就包括了Spring与EJB3.0的开发团队。着眼未来几年的技术走向,JPA作为ORM领域标准化整合者的目标应该不难实现。 JPA的总体思想和现有Hibernate、TopLink、JDO等ORM框架大体一致。总的来说,JPA包括以下3方面的技术:ORM映射元数据JPA支持XML和JDK5.0注解两种元数据形式,元数据描述对象和表之间的映射关系,框架据此将实现对象持久化到数据库表中。Java持久化API用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者可以从繁琐的JDBC和SQL代码中解脱出来。查询语言这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合 参考技术A   JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

  JPA包括以下3方面的技术:

  1.ORM映射元数据。JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;

  2.API。用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。

  3.查询语言。这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。

  
  由于JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
参考技术B Java Persistence API
  JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据中。
参考技术C JPA 即Java Persistence API。

JPA 是一个基于O/R映射的标准规范(目前最新版本是JPA 2.1 )。所谓规范即只定义标准规则(如注解、接口),不提供实现,软件提供商可以按照标准规范来实现,而使用者只需按照规范中定义的方式来使用,而不用和软件提供商的实现打交道。

JPA的出现有两个原因:

简化现有Java EE和Java SE应用的对象持久化的开发工作;
Sun希望整合对ORM技术,实现持久化领域的统一。
JPA 的主要实现有Hibernate、EclipseLink 和OpenJPA 等,这也意味着我们只要使用JPA 来开发,无论是哪一个开发方式都是一样的。
参考技术D JPA的英文全称是Java PersistenceAPI, 目的是给Java开发者提供对象关系映射工具用于在Java应用程序开发中来管理关系数据(RDBMS)。如下特点:
1 标准化
JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问 API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
2 对容器级特性的支持
JPA 框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
3 简单易用,集成方便
JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity进行注释;JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的 掌握。JPA基于非侵入式原则设计,因此可以很容易的和其它框架或者容器集成。
4 可媲美JDBC的查询能力
JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成 是Hibernate HQL的等价物。JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
5 支持面向对象的高级特性
JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。

JPA 实体图的目标是啥?

【中文标题】JPA 实体图的目标是啥?【英文标题】:What's the goal of the JPA Entity Graph?JPA 实体图的目标是什么? 【发布时间】:2015-10-20 14:47:01 【问题描述】:

我一直在学习JPA,发现我们可以从JPA 2.1 开始使用实体图。

但我还没有理解实体图的优点。

我知道使用实体图的优点之一是我们可以只指定我们想要在整个实体中获取的数据,但是如果我们想要一个完整的实体,还有其他理由使用实体图?

或者我们应该只在我们想要检索部分数据时才使用实体图?

如果我们使用实体图有什么其他的目的或优点,我很想知道。

【问题讨论】:

这有帮助吗? radcortez.com/jpa-entity-graphs 谢谢你的链接,它帮了很多忙! 【参考方案1】:

在 JPA/Hibernate 中,获取具有关联的实体一直是 性能问题。

在事务中一次又一次延迟加载关联会导致 n+1 选择问题并避免此类问题 JPQL 使用 join fetch 和 Criteria api 连接。但是用 这两个也导致交叉连接问题意味着所有的交叉连接 表记录由休眠返回给应用程序。 此外,在实体级别更改注释中定义的 fetch 变量也不是基于用例的好选择。 因此引入了实体图来解决上述两个问题。实体图中定义的所有节点总是渴望的 无论它们在实体级别的定义如何,都可以获取。这些 图表作为提示传递给查询。 通过传递图形作为提示,交叉连接问题也得到解决,注释级别指定的关联获取行为可以 也可以更改。

代码可以查看my Github repository。

【讨论】:

【参考方案2】:

JPA Entity Graph 允许您覆盖默认提取计划。

默认提取计划

正如我在 this article 中解释的那样,每个实体都有一个在实体映射期间定义的默认获取计划,并指示 Hibernate 如何获取实体关联。

默认情况下,@ManyToOne@OneToOne 关联使用 FetchTyp.EAGER 策略,从性能角度来看,这是一个糟糕的选择。因此,出于这个原因,最好将所有 @ManyToOne@OneToOne 关联设置为使用 FetchType.LAZY 策略,如下例所示:

@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment 

    @Id
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    private Post post;

    private String review;
    
    //Getters and setters omitted for brevity

当使用find 方法获取PostComment 实体时:

PostComment comment = entityManager.find(PostComment.class, 1L);

Hibernate 执行以下 SQL 查询:

SELECT pc.id AS id1_1_0_,
       pc.post_id AS post_id3_1_0_,
       pc.review AS review2_1_0_
FROM post_comment pc
WHERE pc.id = 1

post 关联作为 Proxy 提取,该关联仅具有由上述 SQL 查询加载的 post_id 外键列设置的 id

访问post代理的任何非id属性时:

LOGGER.info("The comment post title is ''", comment.getPost().getTitle());

执行辅助 SQL 查询,按需获取 Post 实体:

SELECT p.id AS id1_0_0_,
       p.title AS title2_0_0_
FROM post p
WHERE p.id = 1

-- The comment post title is 'High-Performance Java Persistence, part 1'

覆盖默认提取计划

如果我们想覆盖默认获取计划并在查询执行时急切地获取 post 关联,我们可以使用 JPQL 查询来指示 Hibernate 使用 FETCH JOIN 子句获取惰性关联:

PostComment comment = entityManager.createQuery("""
    select pc
    from PostComment pc
    left join fetch pc.post
    where pc.id = :id
    """, PostComment.class)
.setParameter("id", 1L)
.getSingleResult();

LOGGER.info("The comment post title is ''", comment.getPost().getTitle());

然后,默认的获取计划将被覆盖,post 关联将被急切地获取:

SELECT pc.id AS id1_1_0_,
       p.id AS id1_0_1_,
       pc.post_id AS post_id3_1_0_,
       pc.review AS review2_1_0_,
       p.title AS title2_0_1_
FROM post_comment pc
LEFT JOIN post p ON pc.post_id = p.id
WHERE pc.id = 1

声明性 JPA 实体图

也可以使用 JPA 实体图覆盖默认提取计划。例如,我们可以使用以下 JPA @EntityGraph 注释定义特定的获取计划:

@Entity(name = "PostComment")
@Table(name = "post_comment")
@NamedEntityGraph(
    name = "PostComment.post",
    attributeNodes = @NamedAttributeNode("post")
)
public class PostComment 
    //Code omitted for brevity

有了PostComment.post 实体图,我们现在可以加载PostComment 实体及其关联的post 实体,如下所示:

PostComment comment = entityManager.find(
    PostComment.class, 
    1L,
    Collections.singletonMap(
        "javax.persistence.loadgraph",
        entityManager.getEntityGraph("PostComment.post")
    )
);

并且,在执行上述find 方法时,Hibernate 会生成以下 SQL SELECT 查询:

SELECT pc.id AS id1_1_0_,
       pc.post_id AS post_id3_1_0_,
       pc.review AS review2_1_0_,
       p.id AS id1_0_1_,
       p.title AS title2_0_1_
FROM post_comment pc
LEFT OUTER JOIN post p ON pc.post_id = p.id
WHERE pc.id = 1

如果您使用的是 Spring,那么您可以使用 @EntityGraph 注释在 Repository 方法中引用 JPA 实体图:

@Repository
public interface PostCommentRepository 
        extends CrudRepository<PostComment, Long> 

    @EntityGraph(
        value = "PostComment.post", 
        type = EntityGraphType.LOAD
    )
    PostComment findById(Long id);

程序化 JPA 实体图

如果您不喜欢注解,那么您也可以使用 JPA EntityManagercreateEntityGraph 方法以编程方式构建 JPA 实体图,如下例所示:

EntityGraph<PostComment> postCommentGraph = entityManager
    .createEntityGraph(PostComment.class);
    
postCommentGraph.addAttributeNodes("post");

PostComment comment = entityManager.find(
    PostComment.class, 
    1L,
    Collections.singletonMap(
        "javax.persistence.loadgraph",
        postCommentGraph
    )
);

【讨论】:

以上是关于JPA是啥?的主要内容,如果未能解决你的问题,请参考以下文章

JPA - 批量/批量更新 - 更好的方法是啥?

Hibernate @LazyToOne 注释的 JPA 等价物是啥?

JPA @Entity 注解的确切含义是啥?

JPA:迭代大型结果集的正确模式是啥?

实现 Spring Security UserDetails 的 JPA 实体的含义是啥?

Hibernate 作为 JPA 提供者是啥意思? [复制]