SpringDataJPA(一):ORM思想和hibernate以及JPA的概述和基本操作

传统jdbc引出的问题:

主要目的:操作实体类就相当于操作数据库表

  • 建立两个映射关系:
    • 实体类和表的映射关系
    • 实体类中属性和表中字段的映射关系
  • 不再重点关注:sql语句

一、ORM概述

ORM(Object-Relational Mapping) 表示对象关系映射。在面向对象的软件开发中,通过ORM就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射。

简单的说:ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。

1.1 为什么使用ORM

当实现一个应用程序时(不使用O/R Mapping),我们可能会写特别多数据访问层的代码,从数据库保存数据、修改数据、删除数据,而这些代码都是重复的。而使用ORM则会大大减少重复性代码。对象关系映射(Object Relational Mapping,简称ORM),主要实现程序对象到关系数据库数据的映射。

1.2 常见ORM框架

常见的orm框架:Mybatis(ibatis)、Hibernate、Jpa

二、hibernate与JPA的概述

2.1 hibernate概述

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO(Java实体类对象)与数据库表建立映射关系,是一个全自动的ORM框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

2.2 JPA概述

JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。

对比JDBC规范理解JPA:

JPA通过JDK 5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

2.3 JPA的优势
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 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。

2.4 JPA与hibernate的关系

JPA规范本质上就是一种ORM规范,注意不是ORM

JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。

三、JPA的入门案例、JPA中的主键生成策略

创建客户的数据库表:

sql 复制代码
/*创建客户表*/
CREATE TABLE cst_customer (
	cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
	cust_name varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
	cust_source varchar(32) DEFAULT NULL COMMENT '客户信息来源',
	cust_industry varchar(32) DEFAULT NULL COMMENT '客户所属行业',
	cust_level varchar(32) DEFAULT NULL COMMENT '客户级别',
	cust_address varchar(128) DEFAULT NULL COMMENT '客户联系地址',
	cust_phone varchar(64) DEFAULT NULL COMMENT '客户联系电话',
	PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

maven工程导入坐标:pom.xml:

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>top.onefine</groupId>
    <artifactId>jpa_day1</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.hibernate.version>5.4.14.Final</project.hibernate.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
        <!-- hibernate对jpa的支持包 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <!-- Mysql and MariaDB -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>
</project>

配置JPA的核心配置文件:src/main/resources/META-INF/persistence.xml:

在java工程的src路径下创建一个名为META-INF的文件夹,在此文件夹下创建一个名为persistence.xml的配置文件。

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <!-- 配置持久化单元 persistence-unit节点
        name:持久化单元名称
        transaction-type:事务管理的方式
            JTA:分布式事务管理
            RESOURCE_LOCAL:本地事务管理
    -->

    <persistence-unit name="myJPA" transaction-type="RESOURCE_LOCAL">
        <!-- JPA的实现方式 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <properties>
            <!-- 数据库信息 -->
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="963123"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/study_eesy?serverTimezone=UTC"/>
            <!-- 可选配置:配置JPA实现方(如这里是hibernate)的配置信息
                显示sql:hibernate.show_sql
                    true/false
                自动创建数据库表:hibernate.hbm2ddl.auto
                    create  程序运行时创建数据库表(如果有表,删除后再创建)
                    update  程序运行时创建数据库表(如果有表,不会创建表)
                    none    不会创建表
            -->
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>

    </persistence-unit>
</persistence>

创建客户的实体类,及编写实体类和数据库表的映射配置:src/main/java/top/onefine/domain/Customer.java:

注:所有的注解都是使用JPA的规范提供的注解,所以在导入注解包的时候,一定要导入javax.persistence下的。

java 复制代码
package top.onefine.domain;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

import javax.persistence.*;

/**
 * 客户的实体类
 *      配置映射关系:
 *          1. 实体类和表的映射关系
 *              @Entity: 声明实体类
 *              @Table: 配置实体类和表的映射关系
 *                  name:配置数据库表的名称
 *          2. 实体类中属性和表中字段的映射关系
 *              @Id: 声明此属性是对应数据库表中的主键
 *              @GeneratedValue: 配置注解的生成策略
 *                  strategy: 策略
 *                      GenerationType.IDENTITY: 自增,如 mysql
 *                          * 底层数据库必须支持自动增长才可用(底层数据库支持的主动增长方式,对id自增)
 *                      GenerationType.SEQUENCE: 序列,如 oracle
 *                          * 底层数据库必须支持序列才可用
 *                      GenerationType.TABLE: JPA提供的一种机制,通过一张数据库表(hibernate_sequences)的形式帮助我们生成主键自增
 *                      GenerationType.AUTO: 由程序自动的帮助我们选择主键生成策略
 *              @Column: 配置属性和数据库表中字段的映射关系
 *                  name: 数据库表中字段的名称
 *
 */
@Data
@RequiredArgsConstructor()  // custName、custSource构造
@NoArgsConstructor  // 提供空参构造器!!!
@Entity
@Table(name = "cst_customer")
public class Customer {
    // 客户主键
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cust_id")
    private long custId;
    // 客户名称
    @Column(name = "cust_name")
    @NonNull private String custName;
    // 客户来源
    @Column(name = "cust_source")
    @NonNull private String custSource;
    // 客户级别
    @Column(name = "cust_level")
    private String custLevel;
    // 客户所属行业
    @Column(name = "cust_industry")
    private String custIndustry;
    // 客户的联系方式
    @Column(name = "cust_phone")
    private String custPhone;
    // 客户地址
    @Column(name = "cust_address")
    private String custAddress;
}

常用注解说明:

@Entity

作用:指定当前类是实体类。

@Table

作用:指定实体类和表之间的对应关系。

属性:

name:指定数据库表的名称

@Id

作用:指定当前字段是主键。

@GeneratedValue

作用:指定主键的生成方式。

属性:

strategy :指定主键生成策略。

@Column

作用:指定实体类属性和数据库表之间的对应关系

属性:

name: 指定数据库表的列名称。

unique: 是否唯一

nullable: 是否可以为空

inserttable: 是否可以插入

updateable: 是否可以更新

columnDefinition: 定义建表时创建此列的DDL

secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字搭建开发环境[重点]

实现保存操作测试类:src/test/java/top/onefine/test/JpaTest.java:

java 复制代码
package top.onefine.test;

import org.junit.Test;
import top.onefine.domain.Customer;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

/**
 * JPA的操作步骤
 *  1. 加载配置文件创建工厂(实体管理类工厂)对象
 *  2. 通过实体管理器工厂类获取一个实体管理器
 *  3. 获取事务对象,开启事务
 *  4. 完成增删改查操作
 *  5. 提交事务(回滚事务)
 *  6. 释放资源
 */
public class JpaTest {
    /*
    测试数据库的保存操作
     */
    @Test
    public void testSave() {
        // 1. 加载配置文件创建工厂(实体管理类工厂)对象
            // 参数是持久化单元名称,值和persistence.xml中配置一致
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJPA");
        // 2. 通过实体管理器工厂类获取一个实体管理器
        EntityManager entityManager = factory.createEntityManager();
        // 3. 获取事务对象,开启事务
            // 获取事务对象
        EntityTransaction tx = entityManager.getTransaction();
            // 开启事务
        tx.begin();
        // 4. 完成增删改查操作,这里以保存为例
        Customer customer = new Customer("one fine", "java工程师");
            // 保存操作
        entityManager.persist(customer);
        // 5. 提交事务(回滚事务)
        tx.commit();
        // 6. 释放资源
        entityManager.close();
        factory.close();
    }
}

实现保存操作测试类:src/test/java/top/onefine/test/JpaTest.java:

java 复制代码
package top.onefine.test;

import org.junit.Test;
import top.onefine.domain.Customer;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

/**
 * JPA的操作步骤
 *  1. 加载配置文件创建工厂(实体管理类工厂)对象
 *  2. 通过实体管理器工厂类获取一个实体管理器
 *  3. 获取事务对象,开启事务
 *  4. 完成增删改查操作
 *  5. 提交事务(回滚事务)
 *  6. 释放资源
 */
public class JpaTest {
    /*
    测试数据库的保存操作
     */
    @Test
    public void testSave() {
        // 1. 加载配置文件创建工厂(实体管理类工厂)对象
            // 参数是持久化单元名称,值和persistence.xml中配置一致
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJPA");
        // 2. 通过实体管理器工厂类获取一个实体管理器
        EntityManager entityManager = factory.createEntityManager();
        // 3. 获取事务对象,开启事务
            // 获取事务对象
        EntityTransaction tx = entityManager.getTransaction();
            // 开启事务
        tx.begin();
        // 4. 完成增删改查操作,这里以保存为例
        Customer customer = new Customer("one fine", "java工程师");
            // 保存操作
        entityManager.persist(customer);
        // 5. 提交事务(回滚事务)
        tx.commit();
        // 6. 释放资源
        entityManager.close();
        factory.close();
    }
}

四、JPA的API介绍

jpa操作的操作步骤回顾:

1.加载配置文件创建实体管理器工厂

Persisitence:静态方法(根据持久化单元名称创建实体管理器工厂)

createEntityMnagerFactory(持久化单元名称)

作用:创建实体管理器工厂

2.根据实体管理器工厂,创建实体管理器

EntityManagerFactory :获取EntityManager对象

方法:createEntityManager

* 内部维护的很多的内容

内部维护了数据库信息,

维护了缓存信息

维护了所有的实体管理器对象

在创建EntityManagerFactory的过程中会根据配置创建数据库表

* EntityManagerFactory的创建过程比较浪费资源

特点:线程安全的对象

多个线程访问同一个EntityManagerFactory不会有线程安全问题

* 如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题?

思路:创建一个公共的EntityManagerFactory的对象

* 静态代码块的形式创建EntityManagerFactory

3.创建事务对象,开启事务

EntityManager对象:实体类管理器

beginTransaction : 创建事务对象

presist : 保存

merge : 更新

remove : 删除

find/getRefrence : 根据id查询

Transaction 对象 : 事务

begin:开启事务

commit:提交事务

rollback:回滚

4.增删改查操作

5.提交事务

6.释放资源

4.1 Persistence对象

Persistence对象主要作用是用于获取EntityManagerFactory对象的 。通过调用该类的createEntityManagerFactory静态方法,根据配置文件中持久化单元名称创建EntityManagerFactory。

java 复制代码
//1. 创建 EntitymanagerFactory
@Test
String unitName = "myJPA";
EntityManagerFactory factory= Persistence.createEntityManagerFactory(unitName);
4.2 EntityManagerFactory

EntityManagerFactory 接口主要用来创建 EntityManager 实例

java 复制代码
//创建实体管理类
EntityManager em = factory.createEntityManager();

由于EntityManagerFactory 是一个线程安全的对象(即多个线程访问同一个EntityManagerFactory 对象不会有线程安全问题),并且EntityManagerFactory 的创建极其浪费资源,所以在使用JPA编程时,我们可以对EntityManagerFactory 的创建进行优化,只需要做到一个工程只存在一个EntityManagerFactory 即可。

抽取JPAUtil工具类

src\main\java\top\onefine\utils\JpaUtils.java:

java 复制代码
package top.onefine.utils;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 * 解决实体管理器工厂创建时的资源浪费和耗时问题
 *      通过静态代码块的形式,当程序第一次访问此工具类时,创建一个公共的实体管理器工厂对象
 *
 * 步骤:
 *      第一次访问getEntityManager方法:经过静态代码块创建一个factory对象,再创建一个EntityManager对象
 *      第二次访问getEntityManager方法:直接通过一个已经创建好的factory对象创建EntityManager对象
 *
 */
public class JpaUtils {
    private static EntityManagerFactory factory;

    static {
        // 加载配置文件,创建entityManagerFactory
        factory = Persistence.createEntityManagerFactory("myJPA");
    }

    // 获取EntityManager对象
    public static EntityManager getEntityManager() {
        return factory.createEntityManager();
    }
}
4.3 EntityManager

在 JPA 规范中, EntityManager是完成持久化操作的核心对象。实体类作为普通 java对象,只有在调用 EntityManager将其持久化后才会变成持久化对象。EntityManager对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。

我们可以通过调用EntityManager的方法完成获取事务,以及持久化数据库的操作

方法说明:

getTransaction : 获取事务对象

persist : 保存操作

merge : 更新操作

remove : 删除操作

find/getReference : 根据id查询

4.4 EntityTransaction

在 JPA 规范中, EntityTransaction是完成事务操作的核心对象,对于EntityTransaction在我们的java代码中承接的功能比较简单

begin:开启事务

commit:提交事务

rollback:回滚事务

五、使用JPA完成增删改查操作

i.搭建环境的过程

1.创建maven工程导入坐标

2.需要配置jpa的核心配置文件

*位置:配置到类路径下的一个叫做 META-INF 的文件夹下

*命名:persistence.xml

3.编写客户的实体类

4.配置实体类和表,类中属性和表中字段的映射关系

5.保存客户到数据库中

ii.完成基本CRUD案例

persist : 保存

merge : 更新

remove : 删除

find/getRefrence : 根据id查询

iii.jpql查询

sql:查询的是表和表中的字段

jpql:查询的是实体类和类中的属性

* jpql和sql语句的语法相似

1.查询全部

2.分页查询

3.统计查询

4.条件查询

5.排序

5.1 基本CRUD案例------忽略事务回滚
java 复制代码
package top.onefine.test;

import org.junit.Test;
import top.onefine.domain.Customer;
import top.onefine.utils.JpaUtils;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

/**
 * JPA的操作步骤
 *  1. 加载配置文件创建工厂(实体管理类工厂)对象
 *  2. 通过实体管理器工厂类获取一个实体管理器
 *  3. 获取事务对象,开启事务
 *  4. 完成增删改查操作
 *  5. 提交事务(回滚事务)
 *  6. 释放资源
 */
public class JpaTest {
    /*
    测试数据库的保存操作
     */
    @Test
    public void testSave() {
//        // 1. 加载配置文件创建工厂(实体管理类工厂)对象
//            // 参数是持久化单元名称,值和persistence.xml中配置一致
//        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJPA");
//        // 2. 通过实体管理器工厂类获取一个实体管理器
//        EntityManager entityManager = factory.createEntityManager();
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 3. 获取事务对象,开启事务
            // 获取事务对象
        EntityTransaction tx = entityManager.getTransaction();
            // 开启事务
        tx.begin();
        // 4. 完成增删改查操作,这里以保存为例
        Customer customer = new Customer("one fine", "java工程师");
            // 保存操作
        entityManager.persist(customer);
        // 5. 提交事务(回滚事务)
        tx.commit();
        // 6. 释放资源
        entityManager.close();
//        factory.close();  // 不用释放
    }

    /**
     * 根据id查询客户------立即加载
     *  使用find方法查询:
     *      1.查询的对象就是当前客户对象本身
     *      2.在调用find方法的时候,就会发送sql语句查询数据库
     *
     *  立即加载
     */
    @Test
    public void testFind() {
        // 1. 通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 2. 开启事务
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();
        // 3. 增删改查------根据id查询客户
        /*
        find: 根据id查询数据
            class: 查询数据的结果需要包装的实体类型的字节码
            id: 查询的主键的取值
         */
        Customer customer = entityManager.find(Customer.class, 1L);
        System.out.println(customer);

        // 4. 提交事务
        tx.commit();
        // 5. 释放资源
        entityManager.close();
    }

    /**
     * 根据id查询客户------懒加载
     *      getReference方法
     *          1.获取的对象是一个动态代理对象
     *          2.调用getReference方法不会立即发送sql语句查询数据库
     *              * 当调用查询结果对象的时候,才会发送查询的sql语句:什么时候用,什么时候发送sql语句查询数据库
     *
     * 延迟加载(懒加载)--多使用
     *      * 得到的是一个动态代理对象
     *      * 什么时候用,什么使用才会查询
     */
    @Test
    public void testReference() {
        // 1. 通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 2. 开启事务
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();
        // 3. 增删改查------根据id查询客户
        /*
        getReference: 根据id查询数据
            class: 查询数据的结果需要包装的实体类型的字节码
            id: 查询的主键的取值
         */
        Customer customer = entityManager.getReference(Customer.class, 1L);
        System.out.println(customer);

        // 4. 提交事务
        tx.commit();
        // 5. 释放资源
        entityManager.close();
    }

    /**
     * 删除客户
     */
    @Test
    public void testRemove() {
        // 1. 通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 2. 开启事务
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();
        // 3. 增删改查------删除客户
            // 根据id查询客户
        Customer customer = entityManager.find(Customer.class, 3L);
            // 调用remove方法完成删除操作
        if (customer != null) {
            System.out.println(customer + "已删除");
            entityManager.remove(customer);
        }

        // 4. 提交事务
        tx.commit();
        // 5. 释放资源
        entityManager.clear();
    }

    /**
     * 更新客户
     */
    @Test
    public void testUpdate() {
        // 1. 通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 2. 开启事务
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();
        // 3. 增删改查------更新客户
            // 查询客户
        Customer customer = entityManager.find(Customer.class, 1L);
        // 更新客户
        if (customer != null) {
            System.out.println("更新前: " + customer);
            customer.setCustLevel("6段...");
            Customer update_customer = entityManager.merge(customer);

//            System.out.println("更新后: " + entityManager.find(Customer.class, 1L));
            System.out.println("更新后: " + update_customer);
        }
        // 4. 提交事务
        tx.commit();
        // 5. 释放资源
        entityManager.clear();
    }
}
5.2 JPQL查询

JPQL全称Java Persistence Query Language,基于首次在EJB2.0中引入的EJB查询语言(EJB QL),Java持久化查询语言(JPQL)是一种可移植的查询语言,旨在以面向对象表达式语言的表达式,将SQL语法和简单查询语义绑定在一起·使用这种语言编写的查询是可移植的,可以被编译成所有主流数据库服务器上的SQL。

其特征与原生SQL语句类似,并且完全面向对象,通过类名和属性访问,而不是表名和表的属性。

java 复制代码
package top.onefine.test;

import org.junit.Test;
import top.onefine.domain.Customer;
import top.onefine.utils.JpaUtils;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import java.util.List;

/**
 * 测试jpql查询
 *      步骤:
 *          1. 创建query查询对象
 *          2. 对参数进行赋值
 *          3. 查询,并得到返回结果
 */
public class JpqlTest {
    /**
     * 查询全部
     *      jqpl:from [top.onefine.]Customer
     *      sql:select * from cst_customer
     */
    @Test
    public void testFindAll() {
        // 1. 通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 2. 开启事务
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();
        // 3. 查询全部
            // 创建Query查询对象,query对象才是执行jqpl的对象
        String jpql = "from " + /*"top.onefine.domain." + */"Customer";
        Query query = entityManager.createQuery(jpql);
        // 发送查询,并封装结果集
        List<Customer> list = query.getResultList();

        for (Customer customer : list)
            System.out.println(customer);

        // 4. 提交事务
        tx.commit();
        // 5. 释放资源
        entityManager.clear();
    }


    /**
     * 排序查询:根据id倒序查询全部客户
     *      jqpl:from [top.onefine.]Customer order by custId desc
     *      sql:select * from cst_customer order by cust_id desc
     */
    @Test
    public void testOrders() {
        // 1. 通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 2. 开启事务
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();
        // 3. 排序查询
        // 创建Query查询对象,query对象才是执行jqpl的对象
        String jpql = "from " + /*"top.onefine.domain." + */"Customer order by custId desc";  // custId是实体类属性名称
        Query query = entityManager.createQuery(jpql);
        // 发送查询,并封装结果集
        List<Customer> list = query.getResultList();

        for (Customer customer : list)
            System.out.println(customer);

        // 4. 提交事务
        tx.commit();
        // 5. 释放资源
        entityManager.clear();
    }

    /**
     * 统计查询:统计客户的总数
     *      jqpl:select count(custId) from [top.onefine.]Customer
     *      sql:select count(cust_id) from cst_customer
     */
    @Test
    public void testCount() {
        // 1. 通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 2. 开启事务
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();
        // 3. 统计查询
            // 根据jpql语句创建query查询条件
        String jpql = "select count(custId) from " + /*"top.onefine.domain." + */"Customer";  // custId是实体类属性名称
            // 对参数赋值
            // 发送查询,并封装结果
        Query query = entityManager.createQuery(jpql);
//        // 发送查询,并封装结果集
//        List list = query.getResultList();
//
//        for (Object customer : list)
//            System.out.println(customer);
        // 注:getResultList是直接将查询结果封装为list集合
        // getSingleResult得到唯一的结果
        Object result = query.getSingleResult();
        System.out.println((long) result);

        // 4. 提交事务
        tx.commit();
        // 5. 释放资源
        entityManager.clear();
    }

    /**
     * 分页查询
     *      jqpl:from [top.onefine.]Customer
     *      sql:select * from cst_customer limit ?, ? // 占位符,如 limit 0, 2
     */
    @Test
    public void testPaged() {
        // 1. 通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 2. 开启事务
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();
        // 3. 分页查询
            // 根据jpql语句创建query查询条件
        String jpql = "from " + /*"top.onefine.domain." + */"Customer";
        Query query = entityManager.createQuery(jpql);
            // 对参数赋值------分页参数
                // 起始索引
        query.setFirstResult(0);
                // 每页查询的条数
        query.setMaxResults(2);

            // 发送查询,并封装结果
        List list = query.getResultList();

        for (Object customer : list)
            System.out.println(customer);

        // 4. 提交事务
        tx.commit();
        // 5. 释放资源
        entityManager.clear();
    }

    /**
     * 条件查询:查询客户名称以"one"开头的客户
     *      jqpl:from [top.onefine.]Customer where custName like ?
     *      sql:select * from cst_customer where cust_name like ?
     */
    @Test
    public void testCondition() {
        // 1. 通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        // 2. 开启事务
        EntityTransaction tx = entityManager.getTransaction();
        tx.begin();
        // 3. 条件查询
            // 根据jpql语句创建query查询条件
        String jpql = "from " + /*"top.onefine.domain." + */"Customer where custName like ?1";
        Query query = entityManager.createQuery(jpql);
            // 对参数赋值------占位符参数
            // 第一个参数是占位符的索引位置(从1开始),第二个参数是取值
        query.setParameter(1, "one%");

            // 发送查询,并封装结果
        List list = query.getResultList();

        for (Object customer : list)
            System.out.println(customer);

        // 4. 提交事务
        tx.commit();
        // 5. 释放资源
        entityManager.clear();
    }
}
相关推荐
LI JS@你猜啊几秒前
window安装docker
java·spring cloud·eureka
书中自有妍如玉10 分钟前
.net 使用MQTT订阅消息
java·前端·.net
风铃儿~36 分钟前
Spring AI 入门:Java 开发者的生成式 AI 实践之路
java·人工智能·spring
斯普信专业组41 分钟前
Tomcat全方位监控实施方案指南
java·tomcat
忆雾屿1 小时前
云原生时代 Kafka 深度实践:06原理剖析与源码解读
java·后端·云原生·kafka
武昌库里写JAVA1 小时前
iview Switch Tabs TabPane 使用提示Maximum call stack size exceeded堆栈溢出
java·开发语言·spring boot·学习·课程设计
gaoliheng0061 小时前
Redis看门狗机制
java·数据库·redis
我是唐青枫1 小时前
.NET AOT 详解
java·服务器·.net
Su米苏2 小时前
Axios请求超时重发机制
java
Undoom2 小时前
🔥支付宝百宝箱新体验!途韵归旅小帮手,让高铁归途变旅行
后端