什么是JPA?Java Persistence API简介

作为规范,Java Persistence API关注持久性,它将Java对象的创建过程和具体的创建形式解耦。并非所有Java对象都需要持久化,但大多数应用程序都会保留关键业务对象。JPA规范允许您定义应该保留哪些对象,以及如何在Java应用程序中保留这些对象。

JPA本身不是一个工具或框架; 相反,它定义了一组可以由任何工具或框架实现的概念。虽然JPA的对象关系映射(ORM)模型最初基于Hibernate,但它已经发展了。同样,虽然JPA最初打算用于关系/ SQL数据库,但是一些JPA实现已经扩展用于NoSQL数据存储。支持JPA和NoSQL的流行框架是EclipseLink,它是JPA 2.2的参考实现。

JPA和Hibernate

由于它们交织在一起的历史,Hibernate和JPA经常混为一谈。但是,与Java Servlet规范一样,JPA产生了许多兼容的工具和框架; Hibernate只是其中之一。

Hibernate由Gavin King开发,于2002年初发布,是一个用于Java的ORM库。King开发了Hibernate作为持久化实体bean的替代品。该框架非常受欢迎,当时非常需要,它的许多想法都在第一个JPA规范中被采用和编纂。

今天,Hibernate ORM是最成熟的JPA实现之一,并且仍然是Java中ORM的流行选项。Hibernate ORM 5.3.8(撰写本文时的当前版本)实现了JPA 2.2。此外,Hibernate的工具系列已经扩展到包括Hibernate Search,Hibernate Validator和Hibernate OGM等流行工具,后者支持NoSQL的域模型持久性。

什么是Java ORM?

虽然它们的执行不同,但每个JPA实现都提供某种ORM层。为了理解JPA和JPA兼容的工具,您需要掌握ORM。

对象关系映射是一项任务 - 开发人员有充分的理由避免手动执行。像Hibernate ORM或EclipseLink这样的框架将该任务编码为库或框架,即ORM层。作为应用程序体系结构的一部分,ORM层负责管理软件对象的转换,以便与关系数据库中的表和列进行交互。在Java中,ORM层转换Java类和对象,以便可以在关系数据库中存储和管理它们。

默认情况下,持久化对象的名称将成为表的名称,字段将成为列。设置表后,每个表行对应于应用程序中的对象。对象映射是可配置的,但默认值往往效果很好。

图1说明了JPA和ORM层在应用程序开发中的作用。

图1

配置Java ORM层

设置新项目以使用JPA时,需要配置数据存储区和JPA提供程序。您将配置数据存储连接器以连接到您选择的数据库(SQL或NoSQL)。您还将包含和配置JPA提供程序,它是一个框架,如Hibernate或EclipseLink。虽然您可以手动配置JPA,但许多开发人员选择使用Spring的开箱即用支持。有关手动和基于Spring的JPA安装和设置的演示,请参阅下面的“ JPA安装和设置 ”。

Java数据对象

Java Data Objects是一个标准化的持久性框架,它与JPA的不同之处主要在于支持对象中的持久性逻辑,以及它长期以来对使用非关系数据存储的支持。JPA和JDO足够相似,JDO提供者也经常支持JPA。请参阅Apache JDO项目,以了解有关JDO与JPA和JDBC等其他持久性标准相关的更多信息。

Java中的数据持久性

从编程的角度来看,ORM层是一个适配器层:它使对象图的语言适应SQL和关系表的语言。ORM层允许面向对象的开发人员构建持久保存数据的软件,而无需离开面向对象的范例。

使用JPA时,可以创建从数据存储区到应用程序的数据模型对象的映射。您可以定义对象和数据库之间的映射,而不是定义对象的保存和检索方式,然后调用JPA来保存它们。如果您正在使用关系数据库,那么应用程序代码和数据库之间的大部分实际连接将由JDBC(Java数据库连接API)处理。

作为规范,JPA提供元数据注释,您可以使用它来定义对象和数据库之间的映射。每个JPA实现都为JPA注释提供了自己的引擎。JPA规范还提供了PersistanceManager或者EntityManager,它们是与JPA系统联系的关键点(其中您的业务逻辑代码告诉系统如何处理映射对象)。

为了使所有这些更具体,请考虑清单1,这是一个用于为音乐家建模的简单数据类。

清单1. Java中的一个简单数据类

public class Musician {
    private long id;
    private String name;
    private Instrument mainInstrument;
    private ArrayList performances = new ArrayList<Performance>();
    public Musician( long id, String name){
        /* constructor setters... */
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
    public void setMainInstrument(Instrument instr){
        this.instrument = instr;
    }
    public Instrument getMainInstrument(){
        return this.instrument;
    }
    // ...Other getters and setters...
}

清单1中的Musician类用于保存数据。它可以包含原始数据,例如名称字段。它还可以与其他类(如mainInstrumentperformances)保持关系。

Musician存在的原因是包含数据。这种类有时称为DTO或数据传输对象。DTO是软件开发的常见功能。虽然它们包含多种数据,但它们不包含任何业务逻辑。持久化数据对象是软件开发中普遍存在的挑战。

JDBC的数据持久性

Musician类的实例保存到关系数据库的一种方法是使用JDBC库。JDBC是一个抽象层,它允许应用程序发出SQL命令而无需考虑底层数据库实现。

清单2显示了如何使用JDBC 来持久化Musician类。

清单2.插入记录的JDBC

Musician georgeHarrison = new Musician(0, "George Harrison");

    String myDriver = "org.gjt.mm.mysql.Driver";
      String myUrl = "jdbc:mysql://localhost/test";
      Class.forName(myDriver);
      Connection conn = DriverManager.getConnection(myUrl, "root", "");

      String query = " insert into users (id, name) values (?, ?)";
      PreparedStatement preparedStmt = conn.prepareStatement(query);
      preparedStmt.setInt    (1, 0);
      preparedStmt.setString (2, "George Harrison");
      preparedStmt.setString (2, "Rubble");

      preparedStmt.execute();
      conn.close();

// Error handling removed for brevity

清单2中的代码是相当自我记录的。该georgeHarrison对象可以来自任何地方(前端提交,外部服务等),并设置其ID和name字段。然后,对象上的字段用于提供SQL insert语句的值。(PreparedStatement该类是JDBC的一部分,提供了一种将值安全地应用于SQL查询的方法。)

虽然JDBC允许手动配置附带的控件,但与JPA相比,它很麻烦。要修改数据库,首先需要创建一个SQL查询,该查询从Java对象映射到关系数据库中的表。然后,只要对象签名发生更改,就必须修改SQL。使用JDBC,维护SQL本身就成了一项任务。

JPA的数据持久性

现在考虑清单3,我们使用JPA 持久化Musician类。

清单3.使用JPA保留George Harrison

Musician georgeHarrison = new Musician(0, "George Harrison");
musicianManager.save(georgeHarrison);

清单3用一行session.save()替换了清单2中的手动SQL ,它指示JPA持久保存该对象。从那时起,SQL转换由框架处理,因此您永远不必离开面向对象的范例。

JPA中的元数据注释

清单3中的魔力是配置的结果,该配置是使用JPA的注释创建的。开发人员使用注释来告知JPA应该保留哪些对象,以及如何保留它们。

清单4显示了具有单个JPA注释的Musician类。

清单4. JPA的@Entity注释

@Entity
public class Musician {
    // ..class body
}

持久对象有时称为实体。附加@Entity到类,Musician告知JPA应该保留此类及其对象。

配置JPA

与大多数现代框架一样,JPA 遵循约定编码(也称为约定优于配置),其中框架提供基于行业最佳实践的默认配置。作为一个示例,名为Musician的类将默认映射到名为Musician的数据库表。

传统配置是节省时间的,并且在许多情况下它运行良好。也可以自定义JPA配置。例如,您可以使用JPA的@Table注释来指定应该存储Musician类的表。

清单5. JPA的@Table注释

@Entity
@Table(name="musician")
public class Musician {
    // ..class body
}

清单5告诉JPA将实体(Musician类)持久化到musician表中。

主键

在JPA中,主键是用于唯一标识数据库中每个对象的字段。主键可用于引用对象并将对象与其他实体相关联。每当您在表中存储对象时,您还将指定要用作其主键的字段。

在清单6中,我们告诉JPA要使用哪个字段作为Musician主键。

清单6.指定主键

@Entity
public class Musician {
    @Id
       private long id;

在这种情况下,我们使用JPA的@Id注释将id字段指定为Musician主键。默认情况下,此配置假定主键将由数据库设置 - 例如,当字段设置为在表上自动递增时。

JPA支持生成对象主键的其他策略。它还有用于更改单个字段名称的注释。通常,JPA足够灵活,可以适应您可能需要的任何持久性映射。

CRUD操作

将类映射到数据库表并建立其主键后,即可拥有在数据库中创建,检索,删除和更新该类所需的一切。调用session.save()将创建或更新指定的类,具体取决于主键字段是否为null或是否适用于现有实体。调用entityManager.remove()将删除指定的类。

JPA中的实体关系

简单地使用原始字段持久化对象只是方程式的一半。JPA还具有管理彼此相关实体的能力。在表和对象中都有四种实体关系:

  1. 一到多
  2. 许多到一
  3. 许多一对多
  4. 一比一

每种类型的关系描述了实体与其他实体的关系。例如,Musician实体可以与由诸如ListSet的集合表示的实体具有一对多的关系。

如果Musician包含一个Band字段,这些实体之间的关系可以是多对一的,这意味着在单个Band类上有Musician集合 。(假设每个音乐家只在一个乐队中演奏。)

如果Musician包含BandMates字段,则可以表示与其他Musician实体的多对多关系。

最后,Musician可能与Quote实体有一对一的关系,用于表示一个着名的引语:Quote famousQuote = new Quote()

定义关系类型

JPA为每种关系映射类型提供注解。清单7显示了如何注解MusicianPerformances之间的一对多关系。

清单7.注释一对多关系

public class Musician {

  @OneToMany
  @JoinColumn(name="musicianId")
  private List<Performance> performances = new ArrayList<Performance>();
  //...
}

需要注意的一点是@JoinColumn告诉JPA Performance表上的哪一列将映射到Musician实体。每个performance都将与单个Musician关联,该列由此列跟踪。当JPA将一个 Musician或一个Performance 加载到数据库中时,它将使用此信息重新构建对象图。

在JPA中获取策略

除了知道在数据库中放置相关实体​​的位置之外,JPA还需要知道如何加载它们。获取策略告诉JPA如何加载相关实体。加载和保存对象时,JPA框架必须能够微调对象图的处理方式。例如,如果Musician类有一个bandMate字段(如清单7所示),加载george可能导致整个Musician表从数据库加载!

我们需要的是定义相关实体的延迟加载的能力- 当然,认识到JPA中的关系可能是eager或lazy的。您可以使用注释来自定义提取策略,但JPA的默认配置通常可以直接使用,无需更改:

  1. 一对多:lazy
  2. 多对一:eager
  3. 多对多:lazy
  4. 一对一:eager

JPA安装和设置

最后,我们将简要介绍如何为Java应用程序安装和设置JPA。在本演示中,我将使用EclipseLink,即JPA参考实现。

安装JPA的常用方法是在项目中包含 JPA提供程序。清单8显示了如何将EclipseLink作为Maven pom.xml文件中的依赖项包含在内。

清单8.将EclipseLink包含为Maven依赖项

    org.eclipse.persistence
    eclipselink
    2.5.0-RC1

您还需要包含数据库的驱动程序,如清单9所示。

清单9. MySql连接器的Maven依赖关系

mysql
            mysql-connector-java
            5.1.32

接下来,您需要告诉系统您的数据库和提供程序。这在persistence.xml文件中完成,如清单10所示。

清单10. Persistence.xml

http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="MyUnit" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/foo_bar"/>
            <property name="javax.persistence.jdbc.user" value=""/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
        </properties>
    </persistence-unit>
</persistence>

还有其他方法可以向系统提供此信息,包括以编程方式。我建议使用该persistence.xml文件,因为以这种方式存储依赖项使得在不修改代码的情况下更新应用程序非常容易。

JPA的Spring配置

使用Spring将极大地简化JPA与应用程序的集成。例如,将@SpringBootApplication注释放在应用程序头中会指示Spring 根据您指定的配置自动扫描类并根据需要注入EntityManager

如果您希望Spring为您的应用程序提供JPA支持,清单11显示了要包含的依赖项。

清单11.在Maven中添加Spring JPA支持

org.springframework.boot
    spring-boot-starter
    2.1.3.RELEASE
    org.springframework.boot
    spring-boot-starter-data-jpa
    2.1.3.RELEASE

结论

处理数据库的每个应用程序都应该定义一个应用程序层,其唯一目的是隔离持久性代码。正如您在本文中看到的,Java Persistence API引入了一系列功能并支持Java对象持久性。简单的应用程序可能不需要JPA的所有功能,在某些情况下,配置框架的开销可能不值得。然而,随着应用程序的增长,JPA的结构和封装确实能够保持不变。使用JPA可以简化目标代码,并提供用于访问Java应用程序中的数据的传统框架。

读者福利:

分享免费学习资料

针对于Java程序员,我这边准备免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!

资料领取方式:加入Java技术交流群963944895点击加入群聊,私信管理员即可免费领取

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 作为规范,Java Persistence API关注持久性,它将Java对象的创建过程和具体的创建形式解耦。并非...
    Java架构学习者阅读 3,551评论 0 1
  • 在一个方法内部定义的变量都存储在栈中,当这个函数运行结束后,其对应的栈就会被回收,此时,在其方法体中定义的变量将不...
    Y了个J阅读 4,412评论 1 14
  • 一. Java基础部分.................................................
    wy_sure阅读 3,785评论 0 11
  • 作者:钟昕灵,叩丁狼教育高级讲师。原创文章,转载请注明出处。 JPA简介 JPA是Java Persistence...
    叩丁狼教育阅读 4,072评论 1 5
  • “绿蓑江上秋闻笛,红袖楼头夜倚栏”慕雅女雅集苦吟诗一回中呆香菱三易其稿,精血诚聚,终梦中得诗。 《红楼梦...
    涣柒阅读 915评论 2 3