热门标签 | 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后,该实体对象就处于删除状态。其本质也就是一个瞬时状态的对象。

四种状态之间的转换

在这里插入图片描述


推荐阅读
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
  • 如何利用Java 5 Executor框架高效构建和管理线程池
    Java 5 引入了 Executor 框架,为开发人员提供了一种高效管理和构建线程池的方法。该框架通过将任务提交与任务执行分离,简化了多线程编程的复杂性。利用 Executor 框架,开发人员可以更灵活地控制线程的创建、分配和管理,从而提高服务器端应用的性能和响应能力。此外,该框架还提供了多种线程池实现,如固定线程池、缓存线程池和单线程池,以适应不同的应用场景和需求。 ... [详细]
  • 并发编程入门:初探多任务处理技术
    并发编程入门:探索多任务处理技术并发编程是指在单个处理器上高效地管理多个任务的执行过程。其核心在于通过合理分配和协调任务,提高系统的整体性能。主要应用场景包括:1) 将复杂任务分解为多个子任务,并分配给不同的线程,实现并行处理;2) 通过同步机制确保线程间协调一致,避免资源竞争和数据不一致问题。此外,理解并发编程还涉及锁机制、线程池和异步编程等关键技术。 ... [详细]
  • 投融资周报 | Circle 达成 4 亿美元融资协议,唯一艺术平台 A 轮融资超千万美元 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 数字图书馆近期展出了一批精选的Linux经典著作,这些书籍虽然部分较为陈旧,但依然具有重要的参考价值。如需转载相关内容,请务必注明来源:小文论坛(http://www.xiaowenbbs.com)。 ... [详细]
  • 阿里云MySQL与Oracle数据库的主从复制技术详解 ... [详细]
  • 在探讨Hibernate框架的高级特性时,缓存机制和懒加载策略是提升数据操作效率的关键要素。缓存策略能够显著减少数据库访问次数,从而提高应用性能,特别是在处理频繁访问的数据时。Hibernate提供了多层次的缓存支持,包括一级缓存和二级缓存,以满足不同场景下的需求。懒加载策略则通过按需加载关联对象,进一步优化了资源利用和响应时间。本文将深入分析这些机制的实现原理及其最佳实践。 ... [详细]
  • 本文深入探讨了Ajax的工作机制及其在现代Web开发中的应用。Ajax作为一种异步通信技术,改变了传统的客户端与服务器直接交互的模式。通过引入Ajax,客户端与服务器之间的通信变得更加高效和灵活。文章详细分析了Ajax的核心原理,包括XMLHttpRequest对象的使用、数据传输格式(如JSON和XML)以及事件处理机制。此外,还介绍了Ajax在提升用户体验、实现动态页面更新等方面的具体应用,并讨论了其在当前Web开发中的重要性和未来发展趋势。 ... [详细]
  • Vue应用预渲染技术详解与实践 ... [详细]
  • REST与RPC:选择哪种API架构风格?
    在探讨REST与RPC这两种API架构风格的选择时,本文首先介绍了RPC(远程过程调用)的概念。RPC允许客户端通过网络调用远程服务器上的函数或方法,从而实现分布式系统的功能调用。相比之下,REST(Representational State Transfer)则基于资源的交互模型,通过HTTP协议进行数据传输和操作。本文将详细分析两种架构风格的特点、适用场景及其优缺点,帮助开发者根据具体需求做出合适的选择。 ... [详细]
  • 第二章:Kafka基础入门与核心概念解析
    本章节主要介绍了Kafka的基本概念及其核心特性。Kafka是一种分布式消息发布和订阅系统,以其卓越的性能和高吞吐量而著称。最初,Kafka被设计用于LinkedIn的活动流和运营数据处理,旨在高效地管理和传输大规模的数据流。这些数据主要包括用户活动记录、系统日志和其他实时信息。通过深入解析Kafka的设计原理和应用场景,读者将能够更好地理解其在现代大数据架构中的重要地位。 ... [详细]
  • 在 CentOS 6.6 系统中搭建 MONO 和 Jexus 以支持 ASP.NET 及 MVC 应用的运行环境配置指南
    本文提供了在 CentOS 6.6 系统上配置 MONO 和 Jexus 以支持 ASP.NET 及 MVC 应用的详细步骤。首先,确保本机环境为 CentOS 6.6,并使用阿里云的 YUM 源来安装必要的软件包,包括 gcc、gcc-c++、bison、pkgconfig 和 glib2-devel。这些软件包是构建和运行 MONO 环境的基础,确保系统能够顺利支持 ASP.NET 和 MVC 应用的部署和运行。 ... [详细]
  • 本文作为探讨PHP依赖注入容器系列文章的开篇,将首先通过具体示例详细阐述依赖注入的基本概念及其重要性,为后续深入解析容器的实现奠定基础。 ... [详细]
  • 在Python网络编程中,多线程技术的应用与优化是提升系统性能的关键。线程作为操作系统调度的基本单位,其主要功能是在进程内共享内存空间和资源,实现并行处理任务。当一个进程启动时,操作系统会为其分配内存空间,加载必要的资源和数据,并调度CPU进行执行。每个进程都拥有独立的地址空间,而线程则在此基础上进一步细化了任务的并行处理能力。通过合理设计和优化多线程程序,可以显著提高网络应用的响应速度和处理效率。 ... [详细]
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社区 版权所有