Spring 全家桶之 Spring Data JPA(一)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Spring 全家桶之 Spring Data JPA(一)

一、JDBC Template是如何操作数据库的

  1. 首先在数据库创建user表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
复制代码
  1. 创建实体类
public class User{
    private Integer id;
    private String username;
    private String password;
    // 此处省略getter/setter/toString方法
}

3.在applicationContext.xml配置文件中注入jdbcTemplate及数据源的配置

<!-- 数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url"
              value="jdbc:mysql://localhost:3306/test?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>
<!--JdbcTemplate提供数据CRUD的API-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
</bean>

4.在dao层创建UserDao,使用jdbcTemplate

public class UserDao {
    private JdbcTemplate jdbcTemplate;
    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    public User findById(Integer id){
        String sql = "SELECT * FROM user WHERE id=?";
        //BeanPropertyRowMapper主要是进行数据库数据和实体对象之间的转换
        // queryForObject查询单条数据
        User user = jdbcTemplate.queryForObject(sql, new Object[]{id}, new BeanPropertyRowMapper<Employee>(Employee.class));
        return user;
    }
}    

JdbcTemplate虽然简化了原生jdbc的操作,封装了获取数据库连接,创建prepareStatment对象等操作,但是仍然需要在代码中写入SQL语句,并对占位符进行赋值操作,只不过使用preparementStatment.setString赋值操作改为将参数放入数组中进行和占位符的赋值操作,如果想要连SQL语句也封装起来,这样在代码中就不会出现SQL语句了,也就更进一步的简化了JDBC的操作流程。

  以根据ID查询为例,SQL语句为SELECT * FROM user WHERE id=? 其中表明user及主键名称id是变化的,其余部分是固定结构,而实体类名称和属性是与数据库表名和字段是一一对应的,因此可以通过实体类名记属性确定要操作的数据库表和字段的名字,从而可以根据实体类的不同拼接出不同的SQL语句。ORM思想的主要目的就是操作实体类就相当于操作数据库表,这就需要建立两个映射关系,实体类和表映射关系,实体类字段和表属性的映射关系,不再关注SQL语句实现了ORM思想的框架有Hibernate及Mybatis

二、什么是JPA

   JPA是一套规范,内部由接口和抽象类组成,Hibernate就是实现了 JPA规范的ORM框架

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

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

090071d66a5d43d88354147ea81ec734_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

三、如何使用JPA API

3.1 - 基本增删改查实现

  1. 创建Customer实体类对应的数据库表customer
CREATE TABLE 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;
  1. 创建maven项目并加入相关依赖
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.hibernate.version>5.0.7.Final</project.hibernate.version>
</properties>
<dependencies>
    <!-- junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!-- hibernate对jpa的支持包 -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${project.hibernate.version}</version>
    </dependency>
    <!-- c3p0 -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
        <version>${project.hibernate.version}</version>
    </dependency>
    <!-- log日志 -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <!-- Mysql and MariaDB -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.18</version>
    </dependency>
</dependencies>
  1. 配置JPA核心配置文件
<?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>
        <!--可选配置:配置jpa实现方的配置信息-->
        <properties>
            <!-- 数据库信息
                用户名,javax.persistence.jdbc.user
                密码,  javax.persistence.jdbc.password
                驱动,  javax.persistence.jdbc.driver
                数据库地址   javax.persistence.jdbc.url
            -->
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="root"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=Asia/Shanghai"/>
            <!--配置jpa实现方(hibernate)的配置信息
                显示sql           :   false|true
                自动创建数据库表    :  hibernate.hbm2ddl.auto
                        create      : 程序运行时创建数据库表(如果有表,先删除表再创建)
                        update      :程序运行时创建表(如果有表,不会创建表)
                        none        :不会创建表
            -->
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
    </persistence-unit>
</persistence>
  1. 编写客户实体类,配置实体类和表及类属性和表字段之间的映射关系
/**
 * strategy表示的是主键生成策略
   mysql数据库支持主键自增,可以使用IDENTITY
   oracle不支持,要使用SEQUENCE
    AUTO表示自动选择主键生成策略
 */
@Entity //表示是一个实体类
@Table(name = "customer") //映射的表明
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_phone")
    private String custPhone;
    @Column(name = "cust_address")
    private String custAddress;
    // 此处省略了getter/setter/toString方法
}
  1. 在test包中创建类CustomerDaoTest,使用Junit进行JPA测试
public class CustomerDaoTest {
    @Test
    public void testInsert(){
        //1.加载配置文件创建工厂类
        EntityManagerFactory managerFactory = Persistence.createEntityManagerFactory("myJpa");
        //2.通过工厂类获取实例管理器
        EntityManager entityManager = managerFactory.createEntityManager();
        //3.获取事务对象,开启事务
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        Customer customer = new Customer();
        customer.setCustName("Tony Stark");
        customer.setCustSource("FB");
        customer.setCustLevel("VIP");
        customer.setCustIndustry("Military Industry");
        customer.setCustPhone(null);
        customer.setCustAddress("NY");
        //4.增删改查操作
        entityManager.persist(customer);
        //5.提交/回滚事务
        transaction.commit();
        //6.关闭资源
        entityManager.close();
        managerFactory.close();
    }
}

3.2 - JPA中的API对象

Persistence

作用: 根据持久化单元名称创建实体管理器工厂即EntityManagerFactory。

方法: createEntityManagerFactory,静态方法,参数为持久化单元名称,返回EntityManagerFactory

EntityManagerFactory

作用:创建EntityManager对象

方法:createEntityManger, 返回EntityManager对象

特点:EntityManagerFactory的创建过程比较浪费资源,可以在静态代码块内创建EntityManagerFactory

  • 内部维护了数据库连接信息
  • 内部维护了缓存信息
  • 内部维护了所有的实体类管理对象
  • 可以根据配置选在创建或者不创建实体类对应的数据库表

EntityManager

作用:实体类管理器,关于表的操作都在该类上

方法:

  • beginTrabsaction:创建事务
  • presist:保存
  • merge:更新
  • remove:删除
  • find/getRefrence:根据id查询

Transaction

作用:事务控制

方法:

  • begin:开启事务
  • commit:提交事务,更新操作一定要提交事务
  • rollback:回滚

抽取工具类JPAUtils管理工厂类

public class JPAUtils {
    private static EntityManagerFactory managerFactory;
    static {
        managerFactory = Persistence.createEntityManagerFactory("myJpa");
    }
    //获取EntityManager
    public static EntityManager getEntityManager(){
        return managerFactory.createEntityManager();
    }
}

修改CustomerDao,使用JPAUtils

public class CustomerDaoTest {
    @Test
    public void testInsert(){
        //1.加载配置文件创建工厂类
        // EntityManagerFactory managerFactory = Persistence.createEntityManagerFactory("myJpa");
        //2.通过工厂类获取实例管理器
        EntityManager entityManager = JPAUtils.getEntityManager();
        //3.获取事务对象,开启事务
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        Customer customer = new Customer();
        customer.setCustName("Tony Stark");
        customer.setCustSource("FB");
        customer.setCustLevel("VIP");
        customer.setCustIndustry("Military Industry");
        customer.setCustPhone(null);
        customer.setCustAddress("NY");
        //4.增删改查操作
        entityManager.persist(customer);
        //5.提交/回滚事务
        transaction.commit();
        //6.关闭资源
        entityManager.close();
        // managerFactory.close();
    }
}

在CustomerDaoTest中使用find()方法执行查询操作

@Test
public void testFindById(){
    EntityManager entityManager = JPAUtils.getEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    Customer customer = entityManager.find(Customer.class, 1l);
    System.out.println(customer);
    transaction.commit();
    entityManager.close();
}

执行的SQL:Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_address as cust_add2_0_0_, customer0_.cust_industry as cust_ind3_0_0_, customer0_.cust_level as cust_lev4_0_0_, customer0_.cust_name as cust_nam5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_source as cust_sou7_0_0_ from customer customer0_ where customer0_.cust_id=?

输出结果:Customer{custId=1, custName='Tony Stark', custSource='FB', custLevel='VIP', custIndustry='Military Industry', custPhone='null', custAddress='NY'}

在CustomerDaoTest中使用getReference()方法执行查询操作

@Test
public void testGetReferenceById(){
    EntityManager entityManager = JPAUtils.getEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    Customer customer = entityManager.getReference(Customer.class, 1l);
    System.out.println(customer);
    transaction.commit();
    entityManager.close();
}

  find()是在执行完entityManager.find()后返回Customer对象,并在控制台打印SQL语句,即立即加载

  getReference()获取的是动态代理对象,并且方法调用时不会立即发送SQL语句,即什么时候用什么时候执行SQL语句,即懒加载,一般都会使用延迟加载的方式

执行删除操作

@Test
public void testDelete(){
    EntityManager entityManager = JPAUtils.getEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    Customer customer = entityManager.getReference(Customer.class, 1l);
    entityManager.remove(customer);
    System.out.println(customer);
    transaction.commit();
    entityManager.close();
}

执行更新操作

@Test
public void testMerge(){
    EntityManager entityManager = JPAUtils.getEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    Customer customer = entityManager.getReference(Customer.class, 1l);
    customer.setCustName("IronMan Tony Stark");
    entityManager.merge(customer);
    System.out.println(customer);
    transaction.commit();
    entityManager.close();
}

四、JPQL查询

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

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

查询全部

在test package中新建测试类JPQLTest

public class JPQLTest {
    @Test
    public void testFindAll(){
        EntityManager entityManager = JPAUtils.getEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        String jpql = "FROM Customer";
        Query query = entityManager.createQuery(jpql);
        // 发送查询封装结果
        List resultList = query.getResultList();
        for (Object o : resultList) {
            System.out.println(o);
        }
        transaction.commit();
        entityManager.close();
    }
}

f72499c9ff694c2785033182a3c96cfb_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

倒序查询

@Test
public void testFindAllOrderById(){
    EntityManager entityManager = JPAUtils.getEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    String jpql = "FROM Customer ORDER BY custId DESC";
    Query query = entityManager.createQuery(jpql);
    // 发送查询封装结果
    List resultList = query.getResultList();
    for (Object o : resultList) {
        System.out.println(o);
    }
    transaction.commit();
    entityManager.close();
}

07f244495fc94f38ab4ed4566f16be76_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

统计查询

@Test
public void testCount(){
    EntityManager entityManager = JPAUtils.getEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    String jpql = "SELECT COUNT(custId) FROM Customer";
    Query query = entityManager.createQuery(jpql);
    // 发送查询封装结果
    Object resultList = query.getSingleResult();
    System.out.println(resultList.toString());
    transaction.commit();
    entityManager.close();
}

image.png

分页查询

@Test
    public void testPaged(){
        EntityManager entityManager = JPAUtils.getEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        //查询全部
        String jpql = "FROM Customer";
        Query query = entityManager.createQuery(jpql);
        // 对分页参数进行赋值
        //起始索引
        query.setFirstResult(1);
        //每页查询的个数
        query.setMaxResults(1);
        // 发送查询封装结果
        List resultList = query.getResultList();
        for (Object o : resultList) {
            System.out.println(o);
        }
        transaction.commit();
        entityManager.close();
    }
}

image.png

条件查询

@Test
public void testCondition(){
    EntityManager entityManager = JPAUtils.getEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    //查询全部
    String jpql = "FROM Customer WHERE custName LIKE ?";
    Query query = entityManager.createQuery(jpql);
    query.setParameter(1,"Peter%");
    // 发送查询封装结果
    List resultList = query.getResultList();
    for (Object o : resultList) {
        System.out.println(o);
    }
    transaction.commit();
    entityManager.close();
}

image.png

JPQL不支持 ”SELECT * “ 语句


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
存储 Java API
如何使用 Java 记录简化 Spring Data 中的数据实体
如何使用 Java 记录简化 Spring Data 中的数据实体
38 9
|
1月前
|
SQL Java 关系型数据库
Springboot引入jpa来管理数据库
Springboot引入jpa来管理数据库
39 0
Springboot引入jpa来管理数据库
|
1月前
|
SQL Java 数据库连接
springBoot+Jpa(hibernate)数据库基本操作
springBoot+Jpa(hibernate)数据库基本操作
42 0
|
2月前
|
Java 数据库连接 API
【Java笔记+踩坑】Spring Data JPA
从常用注解、实体类和各层编写方法入手,详细介绍JPA框架在增删改查等方面的基本用法,以及填充用户名日期、分页查询等高级用法。
【Java笔记+踩坑】Spring Data JPA
|
3月前
|
安全 Java 数据安全/隐私保护
基于SpringBoot+Spring Security+Jpa的校园图书管理系统
本文介绍了一个基于SpringBoot、Spring Security和JPA开发的校园图书管理系统,包括系统的核心控制器`LoginController`的代码实现,该控制器处理用户登录、注销、密码更新、角色管理等功能,并提供了系统初始化测试数据的方法。
60 0
基于SpringBoot+Spring Security+Jpa的校园图书管理系统
|
3月前
|
Java 关系型数据库 MySQL
|
3月前
|
Java Spring 数据库
怎样动动手指就能实现数据操作?Spring Data JPA背后的魔法揭秘
【8月更文挑战第31天】在Java开发中,数据库交互至关重要。传统的JDBC操作繁琐且难维护,而Spring Data JPA作为集成JPA的数据访问层解决方案,提供了CRUD等通用操作接口,显著减少代码量。通过继承`JpaRepository`,开发者能轻松实现数据的增删改查,甚至复杂查询和分页也不再困难。本文将通过示例详细介绍如何利用Spring Data JPA简化数据访问层的开发,提升代码质量和可维护性。
43 0
|
3月前
|
存储 Java 数据库
|
3月前
|
存储 Java API
|
3月前
|
Java 数据库连接 数据库
Spring Data JPA 与 Hibernate 之区别
【8月更文挑战第21天】
92 0
下一篇
无影云桌面