热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JPA入门使用、JPA优势、JPA环境搭建

JPA入门使用JPA简介JPA由E

JPA入门使用

JPA简介

  • JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分。但它又不限于EJB 3.0,你可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJO提供持久化标准规范,由此可见,经过这几年的实践探索,能够脱离容器独立运行,方便开发和测试的理念已经深入人心了。Hibernate3.2+、TopLink 10.1.3以及OpenJPA都提供了JPA的实现。
  • JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。
  1. JPA包括以下3方面技术:
    • ORM映射元数据:JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;
    • API:用来操作实体对象,执行CRUD操作,框架在后台替代我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。
    • 查询语言:这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。

JPA的优势

回顾以下DAO代码,以查找所有用户为例,直接使用JDBC查询用户的代码如下:

List users = new ArrayList();
User user = null;
try{
Connection conn = DBUtil.getConnection();
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery("select * from users");
while(resultSet.next()){
user = new User();
user.setId(resultSet.getInt(1));
user.setUserName(resultSet.getString(2));
user.setPassword(resultSet.getString(3));
user.setTelephone(resultSet.getString(4));
user.setRegisterDate(resultSet.getDate(5));
user.setSex(resultSet.getInt(6));
users.add(user);
}
}catch(Exception e){
//省略异常处理代码
}finally{
DBUtil.close(resultSet,statement,conn);
}

  • 用JDBC查询返回的是ResultSet对象,ResultSet往往不能直接使用,还需要转换成List,并且通过JDBC查询不能直接得到具体的业务独享。这样在整个查询的过程中,就需要做很多重复性的转换工作。
    使用JPA完成持久化操作,只需要编写如下代码:

EntityManager entityManager = entityManagerFactory.createEntityManager();
TypedQuery<Users> query = entityManager.createQuery("from Users ",Users.class);
List<Users> list = query.getResultList();

  • JPA处理数据库查询时,编写的代码简洁。作为查询结果,可以直接获得一个存储着User实例的List集合实例,能够直接使用,避免了繁琐的重复性的数据转换过程。
    1. 标准化 JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
    2. 容器级特性的支持 JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
    3. 简单方便 JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易地掌握。JPA基于非侵入式原则设计,因此可以很容易地和其它框架或者容器集成。
    4. 查询能力 JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
    5. 高级特性 JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。

JPA环境搭建

在IDE工具中新建Maven工程,使用JPA,需做以下准备工作:

  1. 添加依赖

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.7.Final</version>
</dependency>

  1. 创建JPA配置文件/META-INF/persistence.xml
    JPA配置文件主要用于配置数据库连接和运行时所需的各种特性。配置文件必须创建在/META-INF目录下,如果没有请自行创建。

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<!-- RESOURCE_LOCAL:采用本地事务管理 -->
<persistence-unit name="JPA" transaction-type="RESOURCE_LOCAL">
<!--JPA需要Provider实现,Hibernate是其中之一-->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!--持久化实体类-->
<class>org.hdax.entity.Users</class>
<properties>
<!--数据库方言-->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<!--数据库连接驱动类-->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<!--数据库连接url-->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf-8" />
<!--数据库登录用户名-->
<property name="javax.persistence.jdbc.user" value="root" />
<!--数据库登录密码-->
<property name="javax.persistence.jdbc.password" value="root" />
<!--是否显示sql语句-->
<property name="hibernate.show_sql" value="true" />
<!--自动创建数据库表-->
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
</persistence-unit>
</persistence>

  1. 创建持久化类

@Entity
@Table(name = "smbms_users")
public class Users implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "userCode",columnDefinition = "varchar(15)")
private String userCode;
@Column(name = "userName",columnDefinition = "varchar(15)")
private String userName;
@Column(name = "userPassword",columnDefinition = "varchar(15) NOT NULL")
private String userPassword;
@Column(name = "gender",columnDefinition = "int(10)")
private Integer gender;
@Column(name = "birthday",columnDefinition = "date")
private Date birthday;
@Column(name = "address",columnDefinition = "varchar(30) DEFAULT '地址不详'")
private String address;
@Column(name = "usrRole",columnDefinition = "int(20)")
private Integer usrRole;
@Column(name = "idPicPath",columnDefinition = "varchar(100)")
private String idPicPath;
public Users(){
}
//省略getter & setter 方法
}

注解名称作用
@Entity将当前实体类标注为持久化类
@Table实体类与数据库表进行关联 当表名和实体类名称相同时,可省略name
@name用于指明数据库表名
@Entity将当前实体类标注为持久化类
@catalog用于指明数据库名称
@Id用于将Java字段标记为数据库表主键列
@GeneratedValue数据库将在插入时自动为id字段生成一个值数据到表
@strategy当使用id字段的自动生成值时
@SequenceGenerator序列创建序列生成器
@name序列程序定义名称
@sequenceName数据库序列名称
@Column属性名称与字段名称映射
@GeneratedValue数据库将在插入时自动为id字段生成一个值数据到表
@name映射的列名
@unique是否唯一
@nullable是否允许为空
@length对于字符型列,length属性指定列的最大字符长度
@insertable是否允许插入
@updateable是否允许更新
@columnDefinition定义建表时创建此列的DDL
@secondaryTable从表名。如果此列不建 在主表上(默认是主表),该属性定义该列所在从表的名字
@Transient该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性

使用JPA完成持久化操作

  • 完成了以上工程之后,就可以通过JPA API操作数据库。
    使用JPA操作数据库包括5个步骤:
  1. 读取并解析配置文件

//此处JPA名称要和配置文件中标签persistence-unit属性name值一致
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("JPA");

  1. 创建实体管理器

EntityManager entityManager = entityManagerFactory.createEntityManager();

  1. 开启事务管理器

EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();

  1. 数据库操作

entityManager.persist(users);

  1. 提交/回滚事务

//提交
transaction.commit();
//回滚
transaction.rollback();

使用JPA实现按主键查询

在进行修改或删除操作时,应先加载对象,然后再执行修改或删除操作。JPA提供了两种方法按照主键加载对象:

find()
EntityManager entityManager = entityManagerFactory.createEntityManager();
Users users = entityManager.find(Users.class,1);
System.out.println("查询完成!");
/*运行结果如下:
Hibernate:
select
users0_.id as id1_0_0_,
users0_.address as address2_0_0_,
users0_.birthday as birthday3_0_0_,
users0_.gender as gender4_0_0_,
users0_.idPicPath as idPicPat5_0_0_,
users0_.userCode as userCode6_0_0_,
users0_.userName as userName7_0_0_,
users0_.userPassword as userPass8_0_0_,
users0_.userRole as userRole9_0_0_
from
smbms_user users0_
where
users0_.id=?
查询完成!
*/

getReference()
EntityManager entityManager = entityManagerFactory.createEntityManager();
Users users = entityManager.getReference(Users.class,1);
System.out.println("查询完成!");
/*运行结果如下:
查询完成!
*/

EntityManager entityManager = entityManagerFactory.createEntityManager();
Users users = entityManager.getReference(Users.class,1);
System.out.println(users);
System.out.println("查询完成!");
/*运行结果如下:
Hibernate:
select
users0_.id as id1_0_0_,
users0_.address as address2_0_0_,
users0_.birthday as birthday3_0_0_,
users0_.gender as gender4_0_0_,
users0_.idPicPath as idPicPat5_0_0_,
users0_.userCode as userCode6_0_0_,
users0_.userName as userName7_0_0_,
users0_.userPassword as userPass8_0_0_,
users0_.userRole as userRole9_0_0_
from
smbms_user users0_
where
users0_.id=?
org.hdax.entity.Users@e041f0c
查询完成!
*/

  • 通过对比我们发现: find()方法查询到的对象结果无论我们是否使用,数据库均会执行查询操作,当查询对象不存在时返回null getReference()方法只有在使用了查询对象时才会连接数据库执行查询,当查询对象不存在时返回EntityNotFoundException异常。

修改数据

  • 数据的修改都是需要事务支持的。通过刚刚的查询数据,现在我们可以对数据进行删除操作:

EntityManager entityManager = entityManagerFactory.createEntityManager();
Users users = entityManager.find(Users.class,1);
System.out.println(users.getUserName());
users.setUserName("超级系统管理员");
/*运行结果如下:
Hibernate:
select
users0_.id as id1_0_0_,
users0_.address as address2_0_0_,
users0_.birthday as birthday3_0_0_,
users0_.gender as gender4_0_0_,
users0_.idPicPath as idPicPat5_0_0_,
users0_.userCode as userCode6_0_0_,
users0_.userName as userName7_0_0_,
users0_.userPassword as userPass8_0_0_,
users0_.userRole as userRole9_0_0_
from
smbms_user users0_
where
users0_.id=?
系统管理员
*/

此时虽然通过set方法修改了用户的用户名,但是通过运行结果我们可以看出,数据库并没有执行响应的更新数据操作,所以现阶段的数据库修改只是在程序内存中完成的。那么如果添加事务之后程序的运行又会发生哪些变化呢?

EntityManager entityManager = entityManagerFactory.createEntityManager();
//获得事务对象
EntityTransaction transaction = entityManager.getTransaction();
//开启事务
transaction.begin();
Users users = entityManager.find(Users.class,1);
System.out.println(users.getUserName());
users.setUserName("超级系统管理员");
//提交事务
transaction.commit();
/*运行结果如下:
Hibernate:
select
users0_.id as id1_0_0_,
users0_.address as address2_0_0_,
users0_.birthday as birthday3_0_0_,
users0_.gender as gender4_0_0_,
users0_.idPicPath as idPicPat5_0_0_,
users0_.userCode as userCode6_0_0_,
users0_.userName as userName7_0_0_,
users0_.userPassword as userPass8_0_0_,
users0_.userRole as userRole9_0_0_
from
smbms_user users0_
where
users0_.id=?
系统管理员
Hibernate:
update
smbms_user
set
address=?,
birthday=?,
gender=?,
idPicPath=?,
userCode=?,
userName=?,
userPassword=?,
userRole=?
where
id=?
*/

不难发现,程序自动执行了更新操作,通过查看数据库表数据,数据库中的用户信息同样发生了相应的修改,所以我们在执行增删改操作的时候应当加入相应的事务控制语句。

删除数据

EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Users users = entityManager.find(Users.class,1);
entityManager.remove(users);
transaction.commit();
System.out.println("删除数据成功!");
/*运行结果如下:
Hibernate:
select
users0_.id as id1_0_0_,
users0_.address as address2_0_0_,
users0_.birthday as birthday3_0_0_,
users0_.gender as gender4_0_0_,
users0_.idPicPath as idPicPat5_0_0_,
users0_.userCode as userCode6_0_0_,
users0_.userName as userName7_0_0_,
users0_.userPassword as userPass8_0_0_,
users0_.userRole as userRole9_0_0_
from
smbms_user users0_
where
users0_.id=?
Hibernate:
delete
from
smbms_user
where
id=?
删除数据成功!
*/

JPA中Java对象的四种状态

  • 瞬时(transient):通过new创建对象后,对象并没有like持久化,它并未与数据库中的数据有任何的关联。
  • 持久(persistent):使用EntityManager进行find或者persist操作返回的对象即处于持久状态,此时该对象已经处于持久化上下文中,因此任何对于该实体的更新都会同步到数据库中。
  • 脱管(detached):当事务提交后,处于托管状态的对象就转变为了游离状态。此时该对象已经不处于持久化上下文中,因此任何对于该对象的修改都不会同步到数据库中。
  • 删除(removed):当调用EntityManger对实体进行delete后,该实体对象就处于删除状态。其本质也就是一个瞬时状态的对象。

四种状态之间的转换

在这里插入图片描述


推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
  • 本文探讨了领域驱动设计(DDD)的核心概念、应用场景及其实现方式,详细介绍了其在企业级软件开发中的优势和挑战。通过对比事务脚本与领域模型,展示了DDD如何提升系统的可维护性和扩展性。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • Ralph的Kubernetes进阶之旅:集群架构与对象解析
    本文深入探讨了Kubernetes集群的架构和核心对象,详细介绍了Pod、Service、Volume等基本组件,以及更高层次的抽象如Deployment、StatefulSet等,帮助读者全面理解Kubernetes的工作原理。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
  • 深入了解 Windows 窗体中的 SplitContainer 控件
    SplitContainer 控件是 Windows 窗体中的一种复合控件,由两个可调整大小的面板和一个可移动的拆分条组成。本文将详细介绍其功能、属性以及如何通过编程方式创建复杂的用户界面。 ... [详细]
author-avatar
shilohqiu_144
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有