Spring Data JPA-基础篇(一)

零、本文纲要

一、基础准备

  1. 数据库准备
    ① 建表DDL
  2. 创建Maven工程
    ① pom.xml
    ② persistence.xml
    ③ 创建实体类

二、基础CRUD

  1. 创建测试类
  2. CRUD测试
    ① 测试新增
    ② 测试查询
    ③ 测试更新
    ④ 测试删除

三、JPQL

  1. 查询全部
  2. 测试排序
  3. 测试计数(聚合)
  4. 测试分页查询
  5. 测试条件查询

一、基础准备

JPA是一种规范,Hibernate是具体的实现,帮助我们实现ORM操作。此处我们将进行基础的JPA操作,具体见下文。

1. 数据库准备

① 建表DDL
-- 客户信息表准备
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_phonoe` VARCHAR(64) DEFAULT NULL COMMENT '客户联系电话',
    PRIMARY KEY (`cust_id`) 
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='客户信息表';

2. 创建Maven工程

① pom.xml

a、属性控制

    
    
        UTF-8
        5.0.7.Final
    

b、基础依赖

    
    
        
        
            junit
            junit
            4.12
            test
        
        
        
            org.hibernate
            hibernate-entitymanager
            ${project.hibernate.version}
        
        
        
            org.hibernate
            hibernate-c3p0
            ${project.hibernate.version}
        
        
        
            log4j
            log4j
            1.2.17
        
        
        
            mysql
            mysql-connector-java
            8.0.30
        
    
② persistence.xml

NOTE
JPA的配置文件 persistence.xml ,改文件有两点要求:
a、必须命名为persistence.xml;
b、必须放置于类加载路径下的META-INF包下。

JPA配置文件放置位置.png

NOTE
IDEA中创建 persistence.xml 配置文件的便捷方法:
File → Settings... → Editor → File and Code Templates → ...
具体如下 ⬇ ⬇ ⬇

IDEA中创建JPA配置文件.png

配置文件具体如下:



    
    
        
        org.hibernate.jpa.HibernatePersistenceProvider

        
        
            
            
            
            
            
            
            
            
        
    

③ 创建实体类

Customer 如下:

import javax.persistence.*;

/**
 * 客户实体类
 * → 配置映射关系
 *      1. 实体类和表的映射关系;
 *      2. 实体类中属性和表中字段的映射关系;
 * → 实体类和表的映射关系
 *      ① @Entity:声明实体类;
 *      ② @Table:配置实体类和表的映射关系;
 *          → name:配置数据库表名称;
 * → 实体类中属性和表中字段的映射关系
 *      ① @Id:声明主键的配置;
 *      ② @GeneratedValue:配置主键生成策略;
 *          → strategy:主键策略
 *              a、 GenerationType.IDENTITY  自增,MySQL数据库;
 *                  底层数据库必须支持自动增长,采用数据库自增方式对ID进行自增。
 *              b、 GenerationType.SEQUENCE  序列,Oracle数据库;
 *                  底层数据库支持序列。
 *              c、 GenerationType.TABLE
 *                  JPA提供的一种机制,通过一张数据库表的形式帮助完成主键自增。
 *              d、 GenerationType.AUTO
 *                  由程序自动选择主键生成策略。
 *      ③ Column:实体类属性与表字段映射
 *          → name:数据库表字段名称
 */
@Table(name = "cst_customer")
@Entity
public class Customer {

    /*客户主键*/
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cust_id")
    private Long custId;

    /*客户名称*/
    @Column(name = "cust_name")
    private String custName;

    /*客户资源来源*/
    @Column(name = "cust_source")
    private String custSource;

    /*客户级别*/
    @Column(name = "cust_level")
    private String custLevel;

    /*客户所属行业*/
    @Column(name = "cust_industry")
    private String custIndustry;

    /*客户的联系方式*/
    @Column(name = "cust_phonoe")
    private String custPhone;

    /*客户地址*/
    @Column(name = "cust_address")
    private String custAddress;

    /*
        此处省略get|set方法、构造方法、toString方法等。
    */

}

二、基础CRUD

1. 创建测试类

/**
 * 基础CRUD:
 *      1. Create增   persist
 *      2. Read查    find | getReference
 *      3. Update改   merge
 *      4. Delete删   remove
 */
public class JpaTest {
      ...
}

2. CRUD测试

① 测试新增

NOTE
JPA的操作的一般流程:
a、加载配置文件,使用Persistence创建工厂对象EntityManagerFactory (实体管理器工厂);
b、通过实体管理器工厂获取实体管理器EntityManager;
c、获取事务对象EntityTransaction;
d、开启事务;
e、进行增删改查操作;
f、提交事务|回滚事务;
g、释放资源。

    /**
     * 测试JPA保存
     * 案例:保存一个客户到数据库中
     * JPA操作步骤
     * 1. 加载配置文件,创建工厂对象(实体管理器工厂);
     * 2. 通过实体管理器工厂获取实体管理器;
     * 3. 获取事务对象;
     * 4. 开启事务;
     * 5. 进行增删改查操作;
     * 6. 提交事务|回滚事务;
     * 7. 释放资源。
     */
    @Test
    public void testSave() {
        // 1. 加载配置文件,创建工厂对象(实体管理器工厂)
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
        // 2. 通过实体管理器工厂获取实体管理器
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        // 3. 获取事务对象
        EntityTransaction transaction = entityManager.getTransaction();
        try {
            // 4. 开启事务
            transaction.begin();
            // 5. 进行增删改查操作
            Customer customer = new Customer();
            customer.setCustName("Stone");
            customer.setCustIndustry("Java");
            // 实体管理器entityManager通过persist保存实体
            entityManager.persist(customer);
            // 6. 提交事务
            transaction.commit();
        } catch (Exception e) {
            // 6. 回滚事务
            transaction.rollback();
            e.printStackTrace();
        } finally {
            // 7. 释放资源
            // 释放实体管理器资源
            try {
                entityManager.clear();
                entityManager.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 释放实体管理器工厂资源
            try {
                entityManagerFactory.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

NOTE
由于 EntityManagerFactory 每次创建非常占用资源,而且其本身即是线程安全的,实际使用中可以创建工具类。
具体如下 ⬇ ⬇ ⬇

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

public class JpaEntityManagerUtil {

    private static final EntityManagerFactory entityManagerFactory;

    static {
        // EntityManagerFactory的创建销毁占用资源,而且本身是线程安全的,所以仅加载一次即可
        entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
    }

    public static EntityManager getEntityManager() {
        return entityManagerFactory.createEntityManager();
    }
}

测试使用我们创建的工具类:

    @Test
    public void testUtil() {
        // 1. 通过实体管理器工具类获取实体管理器
        EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
        // 2. 获取事务对象
        EntityTransaction transaction = entityManager.getTransaction();
        try {
            // 3. 开启事务
            transaction.begin();
            // 4. 操作增删改查
            Customer customer = new Customer();
            customer.setCustName("Jeff");
            customer.setCustIndustry("Java");
            // 实体管理器entityManager通过persist保存实体
            entityManager.persist(customer);
            // 5. 提交事务
            transaction.commit();
        } catch (Exception e) {
            // 5. 回滚事务
            transaction.rollback();
            e.printStackTrace();
        } finally {
            // 6. 释放资源
            entityManager.close();
        }
    }
② 测试查询

NOTE
find方法:
a、及时查询;
b、查询出来的是Customer对象本身。

getReference方法:
a、延时查询,当使用到查询结果时再进行查询;
b、查询出来的是Customer对象的代理对象。

    /**
     * find方法:
     *      1. 及时查询;
     *      2. 查询出来的是Customer对象本身;
     */

            Customer customer = entityManager.find(Customer.class, 1L);
            System.out.println(customer);

    /**
     * getReference方法:
     *      1. 延时查询,当使用到查询结果时再进行查询;
     *      2. 查询出来的是Customer对象的代理对象;
     */
            Customer customer = entityManager.getReference(Customer.class, 1L);
            System.out.println(customer);
③ 测试更新

NOTE
更新操作:先查询,后更新。

使用指定主键查询,判断是否存在:
a、存在,进行更新操作;
b、不存在,会按照指定主键策略进行数据插入。

注意:此处并不会按照指定查询的主键进行插入。

            Customer customer = new Customer();
            /*
                设置主键用于查询:
                    ① 存在,则更新数据;
                    ② 不存在,则插入数据(注意:用于查询的主键不作为插入数据的一部分,而是跟据主键策略生成主键)。
            */
            customer.setCustId(4L);
            customer.setCustName("Stone");
            customer.setCustIndustry("Java");
            entityManager.merge(customer);
④ 测试删除

NOTE
删除操作:先查询,后更新。

            // 先查询,后删除
            // ① 跟据ID查询客户
            Customer customer = entityManager.find(Customer.class, 3L);
            // ② 删除指定客户
            entityManager.remove(customer);

三、JPQL

JPQL:Java Persistence Query Language,Java持久化查询语言。

→ 与SQL对比:
1. SQL:查询表和表中的字段;
2. JPQL:查询实体类和类中的属性;

1. 查询全部

NOTE
与基础CRUD不同的地方,使用JPQL进行查询时,我们需要先获取 Query 对象,再使用其对应方法获取结果。

    /**
     * 测试查询全部
     * → 与SQL对比:
     *      1. SQL:SELECT * FROM cst_customer
     *      2. JPQL:FROM com.stone.entity.Customer
     */
    @Test
    public void testFindAll() {
        EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        try {
            transaction.begin();
            // 1. 编写JPQL语句,此处也可以使用简写的方式 "FROM Customer"
            String JPQL = "FROM com.stone.entity.Customer";
            // 2. 创建查询对象
            Query query = entityManager.createQuery(JPQL);
            // 3. 发送查询,获取结果
            List customers = query.getResultList();
            for (Object customer : customers) {
                System.out.println(customer);
            }
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            e.printStackTrace();
        } finally {
            entityManager.close();
        }
    }

2. 测试排序

NOTE
在查询全部的语句后拼接 ORDER BY 规则即可。

    /**
     * 测试排序
     * → 与SQL对比:
     *      1. SQL:SELECT * FROM cst_customer ORDER BY cust_id DESC
     *      2. JPQL:FROM com.stone.entity.Customer ORDER BY custId DESC
     */
    @Test
    public void testOrder() {
        EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        try {
            transaction.begin();
            // 1. 编写JPQL语句,此处也可以使用简写的方式 "FROM Customer ORDER BY custId DESC"
            String JPQL = "FROM com.stone.entity.Customer ORDER BY custId DESC";
            // 2. 创建查询对象
            Query query = entityManager.createQuery(JPQL);
            // 3. 发送查询,获取结果
            List customers = query.getResultList();
            for (Object customer : customers) {
                System.out.println(customer);
            }
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            e.printStackTrace();
        } finally {
            entityManager.close();
        }
    }

3. 测试计数(聚合)

NOTE
在查询全部的语句前拼接 SELECT COUNT(field_name) 聚合条件即可。

    /**
     * 测试计数(聚合)
     * → 与SQL对比:
     *      1. SQL:SELECT COUNT(cust_id) FROM cst_customer
     *      2. JPQL:SELECT COUNT(custId) FROM com.stone.entity.Customer
     *      注意:相比于上述的查询集合及排序,此处多了SELECT关键字。
     */
    @Test
    public void testCount() {
        EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        try {
            transaction.begin();
            // 1. 编写JPQL语句,此处也可以使用简写的方式 "SELECT COUNT(custId) FROM Customer"
            String JPQL = "SELECT COUNT(custId) FROM com.stone.entity.Customer";
            // 2. 创建查询对象
            Query query = entityManager.createQuery(JPQL);
            // 3. 发送查询,获取结果
            Object result = query.getSingleResult();
            System.out.println(result);
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            e.printStackTrace();
        } finally {
            entityManager.close();
        }
    }

4. 测试分页查询

NOTE
相比于其他查询,该查询需要我们给 Query对象 设置相应的属性:
a、使用 setFirstResult 设置分页查询参数(起始索引从0开始);
b、使用 setMaxResults 设置每页容量。

    /**
     * 测试分页查询
     * → 与SQL对比:
     *      1. SQL:SELECT * FROM cst_customer LIMIT ?,?
     *      2. JPQL:FROM com.stone.entity.Customer
     */
    @Test
    public void testPage() {
        EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        try {
            transaction.begin();
            // 编写JPQL语句,此处也可以使用简写的方式 "FROM Customer"
            String JPQL = "FROM com.stone.entity.Customer";
            Query query = entityManager.createQuery(JPQL);
            // query对象 → 设置分页查询参数
            // ① 设置起始索引,起始索引从0开始
            query.setFirstResult(0);
            // ② 设置每页容量
            query.setMaxResults(3);
            List customers = query.getResultList();
            for (Object customer : customers) {
                System.out.println(customer);
            }
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            e.printStackTrace();
        } finally {
            entityManager.close();
        }
    }

5. 测试条件查询

NOTE
类似分页查询,该查询需要我们给 Query对象 设置相应的属性。

setParameter(int position, Object value) 方法有两个参数:
a、第一个参数position:代表占位符所在位置,从1开始计数;
b、第二个参数value:代表具体替换的参数值。

注意:分页索引从0开始计数,参数占位符从1开始计数。

    /**
     * 测试条件查询
     * → 与SQL对比:
     *      1. SQL:SELECT * FROM cst_customer WHERE cust_address LIKE ?
     *      2. JPQL:FROM com.stone.entity.Customer WHERE custAddress LIKE ?
     */
    @Test
    public void testLike() {
        EntityManager entityManager = JpaEntityManagerUtil.getEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        try {
            transaction.begin();
            // 编写JPQL语句,此处也可以使用简写的方式 "FROM Customer WHERE custAddress LIKE ?"
            String JPQL = "FROM com.stone.entity.Customer WHERE custAddress LIKE ?";
            Query query = entityManager.createQuery(JPQL);
            /*
                query对象 → 设置占位符参数值,setParameter(int position, Object value)
                    ① 第一个参数position:代表占位符所在位置,从1开始计数;
                    ② 第二个参数value:代表具体替换的参数值。
             */
            query.setParameter(1, "%Longgang%");
            query.setFirstResult(0);
            query.setMaxResults(3);
            List customers = query.getResultList();
            for (Object customer : customers) {
                System.out.println(customer);
            }
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            e.printStackTrace();
        } finally {
            entityManager.close();
        }
    }

四、结尾

以上即为Spring Data JPA-基础篇的全部内容,感谢阅读。

你可能感兴趣的:(Spring Data JPA-基础篇(一))