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

四种状态之间的转换

在这里插入图片描述


推荐阅读
  • 在使用mybatis进行mapper.xml测试的时候发生必须为元素类型“mapper”声明属性“namespace”的错误项目目录结构UserMapper和UserMappe ... [详细]
  • 本文探讨了一个Web工程项目的需求,即允许用户随时添加定时任务,并通过Quartz框架实现这些任务的自动化调度。文章将介绍如何设计任务表以存储任务信息和执行周期,以及如何通过一个定期扫描机制自动识别并加载新任务到调度系统中。 ... [详细]
  • 本文探讨了在SharePoint环境中使用BDC(Business Data Catalog)时遇到的问题及其解决策略,包括XML文件导入SSP后的不可见性问题以及与远程SQL Server 2005连接的难题。 ... [详细]
  • 本文探讨了Android系统中联系人数据库的设计,特别是AbstractContactsProvider类的作用与实现。文章提供了对源代码的详细分析,并解释了该类如何支持跨数据库操作及事务处理。源代码可从官方Android网站下载。 ... [详细]
  • 本文详细介绍了在MyBatis框架中如何通过#和$两种方式来传递SQL查询参数。使用#方式可以提高执行效率,而使用$则有助于在复杂SQL语句中更好地查看日志。此外,文章还探讨了不同场景下的参数传递方法,包括实体对象、基本数据类型以及混合参数的使用。 ... [详细]
  • java datarow_DataSet  DataTable DataRow 深入浅出
    本篇文章适合有一定的基础的人去查看,最好学习过一定net编程基础在来查看此文章。1.概念DataSet是ADO.NET的中心概念。可以把DataSet当成内存中的数据 ... [详细]
  • 本文探讨了在使用 MyBatis 进行批量数据处理时遇到的参数绑定异常问题,并提供了详细的解决方案。 ... [详细]
  • 我在尝试将组合框转换为具有自动完成功能时遇到了一个问题,即页面上的列表框也被转换成了自动完成下拉框,而不是保持原有的多选列表框形式。 ... [详细]
  • 利用Python在DragonBoard 410c上解析GPS数据获取位置信息
    本文介绍了如何在DragonBoard 410c开发板上使用Python脚本来解析GPS报文,从而获取精确的位置信息。DragonBoard 410c集成了GPS、Wi-Fi和高性能GPU,非常适合用于各种物联网项目。 ... [详细]
  • 深入解析 RuntimeClass 及多容器运行时应用
    本文旨在探讨RuntimeClass的起源、功能及其在多容器运行时环境中的实际应用。通过详细的案例分析,帮助读者理解如何在Kubernetes集群中高效管理不同类型的容器运行时。 ... [详细]
  • 华为云openEuler环境下的Web应用部署实践
    本文详细记录了在华为云openEuler系统上进行Web应用部署的具体步骤,包括配置yum源、安装Apache、MariaDB、PHP及其相关组件,并完成WordPress的安装与配置过程。 ... [详细]
  • 本文介绍了一个基本的同步Socket程序,演示了如何实现客户端与服务器之间的简单消息传递。此外,文章还概述了Socket的基本工作流程,并计划在未来探讨同步与异步Socket的区别。 ... [详细]
  • 本文详细介绍了如何处理Oracle数据库中的ORA-00227错误,即控制文件中检测到损坏块的问题,并提供了具体的解决方案。 ... [详细]
  • 本文将详细介绍如何配置并整合MVP架构、Retrofit网络请求库、Dagger2依赖注入框架以及RxAndroid响应式编程库,构建高效、模块化的Android应用。 ... [详细]
  • 在使用 MySQL 6.0.x 及以上版本的 JDBC 驱动时,若未正确配置 `serverTimezone` 参数,可能会导致连接异常。本文探讨了这一问题的原因及解决方法。 ... [详细]
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社区 版权所有