百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

企业级Java开发之图解JPA核心构件

ccwgpt 2024-09-21 13:44 23 浏览 0 评论

编者按:

企业级的软件开发中,Java一直都是中流砥柱。在Java EE8之后,Oracle公司把企业级Java标准控制权转交Eclipse基金。最新或·和以后的企业级Java将冠名为Jakarta EE。最新的Jakarta EE是和Java EE 8相兼容的。企业级Java标准,包含有一系列的可选且可用规范(参见下图-1),可根据自己的业务需要酌情进行企业模块的选择。我们知道,任何企业应用如果不跟数据库打交道,那都是耍流氓的。在企业级Java的标准组件中,JPA的标准和实现,无疑是非常优秀而突出的。JPA是在积累了20多年的企业级应用的行业经验的基础诞生的,且依然在发展中。所以说,在企业级应用开发中,与数据库的通讯和交互,大力推荐用JPA。

JPA是一组标准和规范,是Java EE中的一块,其最终的实现厂商各有不同(我这里的几篇文章,都是基于eclipselink的),但必须遵循标准。当然,各个标准的最终厂商实现,也或多或少的加入了自己的扩展和特性,可酌情考虑采用。

对于很多开发者来说,或许觉得JPA“太重”了,直接拒绝之。其实不然,JPA的基本设计和构成足够简单和易用。相信通过我的几篇文章,能让你更快更好的掌握JPA的精要,以便在实际业务中采用,让你更多的关注业务逻辑。当然,本问首要目标是构建你的总体框架似的认知和体验,随着后续的示例和实战演示,相信你会更好的理解之。

行文中,尽力长话短说,一看就懂。下面就进入正文介绍。

声明:本文由牛旦教育原创,欢迎转发和收藏。转载请注明来源@牛旦教育IT课堂


1 JPA核心架构

1.1JPA核心组件

作为JAVA EE数据持久化操作的官方标准的JPA,其核心组件结构如下如所示:


组件构图说明:

1)Persistence:此类javax.persistence.Persistence包含获取EntityManagerFactory实例的的静态帮助器方法,此方法是与供应商(JPA实现提供方)无关的,即供应商中立的方法。典型代码示例:

EntityManagerFactory factory = Persistence.createEntityManagerFactory(persistenceUnitName);

persistenceUnitName为我们的配置文件中的持久化单元名称。

使用Persistence类获取EntityManagerFactory不建议经常使用以获取工厂,因为工厂的构建是一个昂贵的操作,代价高昂。我们通常会缓存一个工厂,然后引用它重复使用,尤其在SE环境下,更应如此。此类间接需要引用persistence.xml配置文件。

2)Persistence Unit:为JPA的持久化单元配置文件,即persistence.xml。此文件中可以配置多个持久化单元,即persistence-unit元素可以根据需要配置多个。持久化单元可以认为就是persistence.xml配置文件,示例参考如下:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
         <persistence-unit name="JPADemo" transaction-type="RESOURCE_LOCAL" >   
                  <class>com.nd.jpa.demo.TxDepart</class>
                  <class>com.nd.jpa.demo.TxEmployee</class>
                  <properties>
                          <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
                          <property name="javax.persistence.jdbc.url"
                           value="jdbc:mysql://localhost:33060/mytest?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"/>
                          <property name="javax.persistence.jdbc.user" value="mytest"/>
                          <property name="javax.persistence.jdbc.password" value="mytest"/>
                  </properties>
         </persistence-unit>
</persistence>

EntityManagerFactory: javax.persistence.EntityManagerFactory类是实体管理器EntityManager的工厂,用于创建实体管理器,典型典型代码如下:

EntityManager em = factory.createEntityManager();//从工厂创建实体管理器

4)Persistence Contexts:作为JPA的核心术语,一个持久化单元就是一些实体类的命名配置(项)界定的范围。持久性或持久化上下文就是指的一组受管理(托管)的实体实例集合。每个持久性上下文都与一个持久性单元相关联,将托管实例的类限制在持久性单元定义的集合。若说一个实体实例是受管理(托管)的,意味着它包含在一个持久性上下文中,并且可以由实体管理器对其进行操作。就是因此,我们一个说实体管理器管理着一个持久性上下文,但一个持久化上下文可以对应多个实体管理器。我们可以借由实体管理器来操作持久化上下文中的实体实例(对象)。

理解持久性上下文是理解实体管理器的关键。实体在持久性上下文中的包含或排除将决定对其进行的任何持久性操作的结果。如果持久性上下文参与事务,则托管实体的内存状态将同步到数据库。然而,尽管持久性上下文起着重要的作用,但它实际上对应用程序是不可见的。它总是通过实体管理器间接访问,并假定在我们需要它时它就在那里。

上面所述,结合上图都好理解,但是持久性上下文是如何创建的?何时创建持久性上下文?实体管理器在应用中是如何体现的?这就是它开始变得有趣的地方。随着我们JPA的深入应用,你将能更好的来理解——目前就认为它是一种逻辑性范围管理概念即可。

5)EntityManager:javax.persistence.EntityManager是应用程序使用的主要JPA接口。每个EntityManager管理一组持久对象,并具有用于插入新对象和删除现有对象的API。

注意,在容器之外使用时,EntityManager和EntityTransaction之间存在一对一的关系。EntityManagers还充当查询(Query)实例的工厂。

6)Entity:表示数据(库)存储记录的持久化对象。通常是用Entity注解来表示的一个POJO对象类,可对应数据库里的一张表。

7)EntityTransaction:前面说过,每个EntityManager与单个javax.persistence.EntityTransaction有一对一的关系。EntityTransactions允许将持久化数据上的操作分组到工作单元中,以便这些工作单元要么完全成功,要么完全失败,从而使数据存储保持原始状态。这些全成功或全失败操作对于维护数据完整性非常重要。通常我们在SE环境下(非Java EE环境下),要手动编程来进行实体管理器相关的事务性操作。

8)Query:javax.persistence.Query接口由每个JPA供应商实现,以查找满足特定条件的持久对象。JPA标准支持使用Java持久性查询语言(JPQL)和结构化查询语言(SQL)进行查询。编程时,我们从EntityManager获取查询(Query)实例。

当然,JPA中还有其它一些组件类,这里暂不介绍。

再次强调JPA中还有其它接口,但仅在兼容ejb3的应用程序服务器之外使用。在应用服务器中,EntityManager实例通常被注入式的,这使得手动操作EntityManagerFactory变得不必要,即不需要手动编程实现。此外,应用服务器中的事务是使用标准的应用服务器事务控件器处理的,因此,EntityTransaction也未被使用。简而言之,若在应用服务器外应用,需要编程式操作EntityManagerFactory和事务处理。

1.1JPA配置文件

persistence.xml文件为标准化JPA运行时提供了通用的支持,并用配置元素properties和子元素property为特定厂商提供了兼容支持。JPA的第一步就是在此xml文件中配置持久化单元。此配置文件在通常在源代码根目录下的META-INF目录下(若IDE会生成一个资源目录,则位置一般为:resources\META-INF\persistence.xml)。这里给出一个常规的且较详细的persistence.xml,并作简要解释:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <!-- 定义持久化单元,事务为 服务器管理的全局事务-->
    <persistence-unit name="JPADemo" transaction-type="JTA">
        <jta-data-source>jdbc/ndsa</jta-data-source>
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.newdayedu.sa.entity.SmOrgans</class>
        <!--可以选择通过class元素列出所有的实体.
若不列出所有,则下面配置为false ,以便自动扫描相关实体-->
        <exclude-unlisted-classes>
            false
        </exclude-unlisted-classes>
        <properties>
            <!—配置JPA厂商实现的连接数据库的属性  -->
            <property name="eclipselink.cache.shared.default" value="false" />
        </properties>
</persistence-unit>
<!-- 可配置多个持久化单元 -->
    <!--  <persistence-unit name="demo" transaction-type="RESOURCE_LOCAL">
      <exclude-unlisted-classes>false</exclude-unlisted-classes>
      <properties>
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/ndsa?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true"/>
        <property name="javax.persistence.jdbc.user" value="ndsa"/>
        <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="javax.persistence.jdbc.password" value="ndsa"/>
        <property name="javax.persistence.schema-generation.database.action" value="create"/>
      </properties>
    </persistence-unit>-->
</persistence>

文件主要配置项说明:

1) persistence-unit:配置文件中,持久化单元可以根据需要配置多个,且可以是异构的数据库;

2) persistence-unit的属性name:为管理器工厂所有的唯一名称;

3) persistence-unit的属性transaction-type:有两种类型JTA和 RESOURCE_LOCAL ;通常在Java EE服务器下选JTA,在SE下使用RESOURCE_LOCAL 。前者的事务交给服务器管理,后者一般要手动控制事务,通过EntityTransaction来进行事务的处理。

4) 子元素provider:指定JPA特定厂商的实现类,即持久化提供器。若应用中只有一种特定的提供器(一般应用服务器会提供),如无特别的元数配置要求,可以不用显式声明,若有多个持久化单元,且有不同的提供商来实现持久化器,则需要显式声明。

5) 子元素jta-data-source/ non-jta-data-source:这里要知道,持久性单元元数据的一个基本功能属性,是描述提供者应该从何处获取数据库连接(属性)以读写实体数据。目标数据库是根据位于服务器JNDI空间中的JDBC数据源的名称指定的(服务器配置托管的数据源)。这个数据源必须是全局可访问的,以便提供器(JPA的实现)在部署持久性应用程序时要访问它。因此典型的情况是使用JTA事务,因此应该在jta-data-source元素中指定JTA数据源的名称。类似地,如果持久性单元的事务类型是本地化资源的,则应该使用non-jta-data-source元素。尽管JPA定义了用于指定数据源名称的标准元素,但它并没有规定格式。在过去,通过在服务器特定的配置文件或管理控制台中进行配置,数据源在JNDI中是可用的(不管JTA还是非JTA型数据源)。这个名称并非官方可移植的,但实际上它们通常是jdbc/SomeDataSource的形式。

有些JPA(的实现)提供器通过与当前JTA事务无关的数据库连接(非JTA连接)来提供高性能的读取操作。然后返回查询结果并使其与持久性上下文的内容一致。这样提高了应用程序的可伸缩性,因为数据库连接直到以后绝对需要时(通常是在提交时)才会参与到JTA事务中。所以为了支持这些可伸缩的读取,除了jta-data-source元素外,还提供non-jta-data-source元素值。比如如下示例:

<persistence-unit name="EmployeeService">
    <jta-data-source>java:app/jdbc/EmployeeDS</jta-data-source>
    <non-jta-data-source>java:app/jdbc/NonTxEmployeeDS</non-jta-data- source>
</persistence-unit>

请注意,EmployeeDS是一个规则配置的数据源,用于访问employee数据库,而NonTxEmployeeDS是一个单独的数据源,用于访问相同的employee数据库,但不参与到JTA事务中。说白了,这两个数据源都是容器相关的JNDI服务,在SE环境下,根本不用考虑这两项配置。

6) 子元素mapping-file*:实体和可嵌入类的XML映射文件的资源名。也还可以在META-INF目录中的一个orm.xml文件中指定映射信息。如果存在,将自动读取orm.xml映射文件。可出现零到多个映射文件。

7) 子元素jar-file*:包含实体和可嵌入类的jar文件的名称。JPA实现将扫描这个jar以查找相关注释的类。可出现零到多个。

8) 子元素class*: 实体和可嵌入类的类名,可并列出现零到多个。

还有其它几个配置元素,很少用,或说一般不用,具体就不再赘述。感兴趣的可自行查看persistence元素定义。

1.1JPA应用案例

为了对上述JPA的核心构成有个更直观的感受,我们这里给了两个示例作为对比总结。若一时不能理解,没关系,继续看完就可以掌握JPA的基本应用了。

1.1.1 SE环境下应用

下面的示例说明了JPA接口如何交互来执行JPQL查询和更新持久化对象。该示例假设在容器外部执行(非Java EE环境)。主要示例代码如下:

public class JPADemo {
 
         public static void main(String[] args) {
                  //获取实体管理器工厂
                  EntityManagerFactory factory = Persistence.createEntityManagerFactory("JPADemo");
                  // 从工厂获取实体管理器EntityManager
                  EntityManager em = factory.createEntityManager();
                  // 开始事务
                  em.getTransaction().begin();
                  // 查询所有在研究部门工作,且平均每周工作超过40小时的员工
                  Query query = em.createQuery("SELECT e " +
                  " FROM Employee e " +
                  " WHERE e.division.name = 'Research' " +
                  " AND e.avgHours > 40");
                  List results = query.getResultList();
                  // 给这些努力工作的员工加薪
                  for (Object res : results) {
                          Employee emp = (Employee) res;
                          emp.setSalary(emp.getSalary() * 1.1);
                  }
                  // 提交(commit)将检测所有更新了的实体,然后将它们保存在数据库中
                  em.getTransaction().commit();
                  // 关闭实体管理器,释放资源
                  em.close();
         }
}


1.1.2 容器环境下应用

在容器中,EntityManager将被注入,事务将以声明的方式处理。因此,容器内的示例本版,将完全由业务逻辑组成,实例代码如下:

    @PersistenceContext(unitName = "JPADemo")
    private EntityManager em;
         ……
         // 查询所有在研究部门工作,且平均每周工作超过40小时的员工
         // -注意,这里的实体管理器(EntityManager) em使用@PersistenceContext
         // 或@Resource注解注入的,其创建由应用服务器完成,这里直接引用
         Query query = em.createQuery("select e from Employee e where "
         + "e.division.name = 'Research' and e.avgHours > 40");
         List results = query.getResultList();
         // 给努力工作的员工加薪,事务有容器管理
         for (Object res : results) {
                  emp = (Employee) res;
                  emp.setSalary(emp.getSalary() * 1.1);
         }
         ……

在前两个应用示例中,对于应用程序管理的实体管理器,在Java SE和Java EE环境之间的区别,不在于如何创建实体管理器,而在于如何获得工厂。

本篇内容到此介绍,请一定仔细看看,理解JPA的总体性机制,后续在慢慢深入,若一下就深入细节,结果就是让你很想放弃。

下一篇我会介绍JPA的核心接口以及相关API。在此系列介绍后,我会在给出一个完整的JPA工程,以供你进一步实战操练。

敬请期待吧 ^_^



欢迎点赞、收藏、转发;若能打赏一二,那一准会点燃我更多的创作激情的 ^_^

相关推荐

团队管理“布阵术”:3招让你的团队战斗力爆表!

为何古代军队能够以一当十?为何现代企业有的团队高效似“特种部队”,有的却松散若“游击队”?**答案正隐匿于“布阵术”之中!**今时今日,让我们从古代兵法里萃取3个核心要义,助您塑造一支战斗力爆棚的...

知情人士回应字节大模型团队架构调整

【知情人士回应字节大模型团队架构调整】财联社2月21日电,针对原谷歌DeepMind副总裁吴永辉加入字节跳动后引发的团队调整问题,知情人士回应称:吴永辉博士主要负责AI基础研究探索工作,偏基础研究;A...

豆包大模型团队开源RLHF框架,训练吞吐量最高提升20倍

强化学习(RL)对大模型复杂推理能力提升有关键作用,但其复杂的计算流程对训练和部署也带来了巨大挑战。近日,字节跳动豆包大模型团队与香港大学联合提出HybridFlow。这是一个灵活高效的RL/RL...

创业团队如何设计股权架构及分配(创业团队如何设计股权架构及分配方案)

创业团队的股权架构设计,决定了公司在随后发展中呈现出的股权布局。如果最初的股权架构就存在先天不足,公司就很难顺利、稳定地成长起来。因此,创业之初,对股权设计应慎之又慎,避免留下巨大隐患和风险。两个人如...

消息称吴永辉入职后引发字节大模型团队架构大调整

2月21日,有消息称前谷歌大佬吴永辉加入字节跳动,并担任大模型团队Seed基础研究负责人后,引发了字节跳动大模型团队架构大调整。多名原本向朱文佳汇报的算法和技术负责人开始转向吴永辉汇报。简单来说,就是...

31页组织效能提升模型,经营管理团队搭建框架与权责定位

分享职场干货,提升能力!为职场精英打造个人知识体系,升职加薪!31页组织效能提升模型如何拿到分享的源文件:请您关注本头条号,然后私信本头条号“文米”2个字,按照操作流程,专人负责发送源文件给您。...

异形柱结构(异形柱结构技术规程)

下列关于混凝土异形柱结构设计的说法,其中何项正确?(A)混凝土异形柱框架结构可用于所有非抗震和抗震设防地区的一般居住建筑。(B)抗震设防烈度为6度时,对标准设防类(丙类)采用异形柱结构的建筑可不进行地...

职场干货:金字塔原理(金字塔原理实战篇)

金字塔原理的适用范围:金字塔原理适用于所有需要构建清晰逻辑框架的文章。第一篇:表达的逻辑。如何利用金字塔原理构建基本的金字塔结构受众(包括读者、听众、观众或学员)最容易理解的顺序:先了解主要的、抽象的...

底部剪力法(底部剪力法的基本原理)

某四层钢筋混凝土框架结构,计算简图如图1所示。抗震设防类别为丙类,抗震设防烈度为8度(0.2g),Ⅱ类场地,设计地震分组为第一组,第一自振周期T1=0.55s。一至四层的楼层侧向刚度依次为:K1=1...

结构等效重力荷载代表值(等效重力荷载系数)

某五层钢筋混凝土框架结构办公楼,房屋高度25.45m。抗震设防烈度8度,设防类别丙类,设计基本地震加速度0.2g,设计地震分组第二组,场地类别为Ⅱ类,混凝土强度等级C30。该结构平面和竖向均规则。假定...

体系结构已成昭告后世善莫大焉(体系构架是什么意思)

实践先行也理论已初步完成框架结构留余后人后世子孙俗话说前人栽树后人乘凉在夏商周大明大清民国共和前人栽树下吾之辈已完成结构体系又俗话说青出于蓝而胜于蓝各个时期任务不同吾辈探索框架结构体系经历有限肯定发展...

框架柱抗震构造要求(框架柱抗震设计)

某现浇钢筋混凝土框架-剪力墙结构高层办公楼,抗震设防烈度为8度(0.2g),场地类别为Ⅱ类,抗震等级:框架二级,剪力墙一级,混凝土强度等级:框架柱及剪力墙C50,框架梁及楼板C35,纵向钢筋及箍筋均采...

梁的刚度、挠度控制(钢梁挠度过大会引起什么原因)

某办公楼为现浇钢筋混凝土框架结构,r0=1.0,混凝土强度等级C35,纵向钢筋采用HRB400,箍筋采用HPB300。其二层(中间楼层)的局部平面图和次梁L-1的计算简图如图1~3(Z)所示,其中,K...

死要面子!有钱做大玻璃窗,却没有钱做“柱和梁”,不怕房塌吗?

活久见,有钱做2层落地大玻璃窗,却没有钱做“柱子和圈梁”,这样的农村自建房,安全吗?最近刷到个魔幻施工现场,如下图,这栋5开间的农村自建房,居然做了2个全景落地窗仔细观察,这2个落地窗还是飘窗,为了追...

不是承重墙,物业也不让拆?话说装修就一定要拆墙才行么

最近发现好多朋友装修时总想拆墙“爆改”空间,别以为只要避开承重墙就能随便砸!我家楼上邻居去年装修,拆了阳台矮墙想扩客厅,结果物业直接上门叫停。后来才知道,这种配重墙拆了会让阳台承重失衡,整栋楼都可能变...

取消回复欢迎 发表评论: