SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂)

时间:2022-07-18 02:00:56

SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂)

  当前环境说明:

  Windows10_64

  Maven3.x

  JDK1.8

  MySQL5.6

  SpringToolSuite4(Spring官方提供的开发工具,实际就是一个Eclipse)

一.整合JdbcTemplate

1.概述

  在实际项目中,在对数据库访问层对数据库进行操作时,大部分时候我们都用的MyBatis/Hibernate,但是偶尔会有用到使用JDBC的时候,一般使用JDBC的话要么就自己封装一个JDBC连接池进行使用,要么就是使用Apache Common 提供的 DbUtils 工具类,还有个就是Spring JDBC ,提供的JdbcTemplate 工具类。

  Spring属于一栈式框架,针对JAVAEE三层中的每一层,都提供了解决技术。在DAO层中Spring中使用JdbcTemplate完成技术需求。(详情请关注后续发表Spring集)

 1 JdbcTemplate中常用类介绍:
2 DriverManagerDataSource类:DataSource连接池的实现子类
3 作用:主要是设置连接数据库的相关信息。如:连接地址、用户名、密码等
4 常用方法:
5 setDriverClassName(……):设置驱动类
6 setUsername(……):设置用户名
7 setPassword(……):设置密码
8 setUrl(……):设置连接地址
9 JdbcTemplate类:
10 作用:由Spring提供的JDBC操作模板类。用于完成CURD操作
11 常用构造方法:
12 JdbcTemplate(DataSource dataSource):创建对象并指定连接管理源
13 常用其他方法:
14 update(……):执行增、删、改。返回值为int类型,表示结果影响行数。
15 queryXXX(……);执行查询。更多请关注博主Spring全集案例

2.准备工作

  1. 创建数据库。
    SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂)
  2. 新增对应数据库实体类。
    1 @Data
    2 @AllArgsConstructor
    3 @NoArgsConstructor
    4 public class Person {
    5 private Integer id;
    6 private String name;
    7 private String password;
    8 }
  3. 修改pom.xml引入依赖
    SpringBoot引入MySQL驱动默认版本为8.x,可以手动配置版本。
     1 <!-- SpringBoot整合JdbcTemplate -->
    2 <dependency>
    3 <groupId>org.springframework.boot</groupId>
    4 <artifactId>spring-boot-starter-jdbc</artifactId>
    5 </dependency>
    6
    7 <!-- MySQL驱动(SpringBoot默认引入版本为8.x)手动配置版本 -->
    8 <dependency>
    9 <groupId>mysql</groupId>
    10 <artifactId>mysql-connector-java</artifactId>
    11 <scope>runtime</scope>
    12 </dependency>
  4. 修改application.yml文件添加数据源配置
     1 spring:
    2 datasource:
    3 #根据MySQL版本配置驱动类5.x----8.x 驱动类“com.mysql.jdbc.Driver” 或 “com.mysql.cj.jdbc.Driver”。
    4 driver-class-name: com.mysql.cj.jdbc.Driver
    5 #useSSL:SSL协议提供服务主要作用:(不建议在没有服务器身份验证的情况下建立SSL连接。)
    6 # 1)认证用户服务器,确保数据发送到正确的服务器;    .
    7 # 2)加密数据,防止数据传输途中被窃取使用;
    8 # 3)维护数据完整性,验证数据在传输过程中是否丢失;
    9 #serverTimezone:设置时区,不设置会报错。GMT%2B8:东八区北京时间 Asia/Shanghai:上海时间
    10 #useServerPrepStmts:在url中给出useServerPrepStmts=true参数,开启预编译(默认PS是关闭的)
    11 #allowMultiQueries:设置为true,开启批量执行sql的开关。更多请持续关注博主文档
    12 url: jdbc:mysql://localhost:3306/springboot?useSSL=false&serverTimezone=GMT%2B8
    13 username: root
    14 password: xsge

3.整合实现

  1. 编写DAO层基础的CURD。
    使用注解@Repository标注为Spring--DAO层组件。注入JdbcTemplate对象
    BeanPropertyRowMapper是JdbcTemplate提供的一个结果集处理器类,是RowMapper结果集处理器接口的实现。
    注意:两个查询方法不一样
     1 @Repository    // Spring注解标注DAO层组件
    2 public class PersonDao{
    3
    4 @Autowired // 注入jdbcTemplate
    5 private JdbcTemplate jdbcTemplate;
    6
    7 /**
    8 * 插入数据
    9 */
    10 public void insertPerson(Person p) {
    11 jdbcTemplate.update("INSERT INTO person(name,password) VALUES (?,?)",
    12 p.getName(),p.getPassword());
    13 }
    14 /**
    15 * 根据ID查询
    16 * 方法queryForObject可以查询单行单列,也可以查询单行多列
    17 * 参数1:SQL
    18 * 参数2:一个类型 或者 一个结果集处理器(取决于查询的结果和需求)
    19 * 参数3:可变参数
    20 */
    21 public Person selectPersonById(Integer id) {
    22 Person person = jdbcTemplate.queryForObject("SELECT * FROM person WHERE id =?",
    23 new BeanPropertyRowMapper<Person>(Person.class), id);
    24 return person;
    25 }
    26 /**
    27 * 查询所有
    28 * 方法query可以查询多行多列。
    29 * 参数1:SQL
    30 * 参数2:一个结果集处理器(取决于查询的结果和需求)
    31 * 参数3:可变参数
    32 */
    33 public List<Person> selectPersonList() {
    34 List<Person> personList = jdbcTemplate.query("SELECT * FROM person",
    35 new BeanPropertyRowMapper<Person>(Person.class));
    36 return personList;
    37 }
    38
    39 }
  2. 编写Service接口
     1 public interface PersonService {
    2 /**
    3 * 新增
    4 */
    5 void insertPerson(Person p);
    6 /**
    7 * 查询一个
    8 */
    9 Person selectPersonById(Integer id);
    10 /**
    11 * 查询多个
    12 */
    13 List<Person> selectPersonList();
    14
    15 }
  3. 编写Service实现类
    使用注解@Service标注为Spring组件。注入DAO对象
     1 @Service
    2 public class PersonServiceImpl implements PersonService {
    3
    4 @Autowired
    5 private PersonDao personDao;
    6
    7 @Override
    8 public void insertPerson(Person p) {
    9 personDao.insertPerson(p);
    10 }
    11
    12 @Override
    13 public Person selectPersonById(Integer id) {
    14 return personDao.selectPersonById(id);
    15 }
    16
    17 @Override
    18 public List<Person> selectPersonList() {
    19 return personDao.selectPersonList();
    20 }
    21
    22 }
  4. 编写Controller,提供一组restFUL风格的接口
    使用注解@RestController标注控制器类,使其返回数据结果都是JSON格式。注入Service对象,使用RestFUL风格提供访问接口
     1 @RestController
    2 public class PersonController {
    3
    4 @Autowired
    5 private PersonService personService;
    6
    7 /**
    8 * 接口地址:http://localhost:8080/insertPerson
    9 * 请求方式:PUT 入参:JSON数据
    10 */
    11 @RequestMapping(value = "/insertPerson", method = RequestMethod.PUT)
    12 public void insertPerson(@RequestBody Person p) {
    13 personService.insertPerson(p);
    14 };
    15 /**
    16 * 接口地址:http://localhost:8080/selectPersonById/1
    17 * 请求方式:GET 入参:id
    18 */
    19 @GetMapping(value = "/selectPersonById/{id}")
    20 public Person selectPersonById(@PathVariable Integer id) {
    21 System.err.println("id值为:"+id);
    22 return personService.selectPersonById(id);
    23 };
    24 /**
    25 * 接口地址:http://localhost:8080/selectPersonList
    26 * 请求方式:POST 入参:无
    27 */
    28 @PostMapping("/selectPersonList")
    29 public List<Person> selectPersonList(){
    30 return personService.selectPersonList();
    31 };
    32 }
  5. 安装Postman工具,访问测试接口。
    启动SpirngBoot项目主程序,请求接口测试!
    Postman是一款常用的接口测试工具,可以测试发送不同请求,传递不同参数,具体操作请关注博主尽情期待。PostMan下载地址
    SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂)

二.整合JPA

  JPA是Java Persistence API的简称,中文名Java持久层API是SUN公司推出的一套基于ORM的规范。Hibernate框架中提供了JPA的实现,Spring Data JPASpring基于Hibernate开发的一个JPA框架。可以极大的简化JPA的写法,可以在几乎不用写具体代码的情况下,实现对数据的访问和操作。除了CRUD外,还包括如分页排序等一些常用的功能。此外更强大的是,它还可以通过方法命名规则进行数据库查询操作

  Spring Data JPA提供的接口:

  1. Repository:最顶层的接口,是一个空的接口,目的是为了统一所有Repository的类型,且能让组件扫描的时候自动识别。
  2. CrudRepository :是Repository的子接口,提供CRUD的功能(内置默认的简单的CURD方法,可以直接引用)
  3. PagingAndSortingRepository:是CrudRepository的子接口,添加分页和排序的功能。
  4. JpaRepository:是PagingAndSortingRepository的子接口,增加了一些实用的功能,比如:批量操作等。(相对最完整的内置方法:简单的CURD/分页/批量)
  5. JpaSpecificationExecutor:用来做负责查询的接口
  6. Specification:是Spring Data JPA提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可。

其中,自定义查询,方法名命名规范如下:

命名可选关键字 方法命名举例 执行方法时对应产生的SQL,Where子句
And findByNameAndPwd where name= ? and pwd =?
Or findByNameOrSex where name= ? or sex=?
Is,Equals findById,findByIdEquals where id= ?
Between findByIdBetween where id between ? and ?
LessThan findByIdLessThan where id < ?
LessThanEquals findByIdLessThanEquals where id <= ?
GreaterThan findByIdGreaterThan where id > ?
GreaterThanEquals findByIdGreaterThanEquals where id > = ?
After findByIdAfter where id > ?
Before findByIdBefore where id < ?
IsNull findByNameIsNull where name is null
isNotNull,NotNull findByNameNotNull where name is not null
Like findByNameLike where name like ?
NotLike findByNameNotLike where name not like ?
StartingWith findByNameStartingWith where name like ‘?%’
EndingWith findByNameEndingWith where name like ‘%?’
Containing findByNameContaining where name like ‘%?%’
OrderBy findByIdOrderByXDesc where id=? order by x desc
Not findByNameNot where name <> ?
In findByIdIn(Collection<?> c) where id in (?)
NotIn findByIdNotIn(Collection<?> c) where id not in (?)
True findByAaaTue where aaa = true
False findByAaaFalse where aaa = false
IgnoreCase findByNameIgnoreCase where UPPER(name)=UPPER(?)

这个确实,够强大!但查询条件一多,这个方法名就也会很长了哦……

  Spring Data JPA简单总结:

  1. 提供了基本的CURD方法,批处理,分页方法等。
  2. 允许自定义方法名,根据指定命名规则实现查询。
  3. 允许使用@Query注解,自定义更高级,更复杂的SQL

1.准备工作

  1. 引入spring-data-jap依赖
    1 <!-- SpringBoot整合JPA -->
    2 <dependency>
    3 <groupId>org.springframework.boot</groupId>
    4 <artifactId>spring-boot-starter-data-jpa</artifactId>
    5 </dependency>
  2. 修改yml配置文件设置JPA配置及数据库配置
     1 spring:
    2 datasource:
    3 #根据MySQL版本配置驱动类5.x----8.x 驱动类“com.mysql.jdbc.Driver” 或 “com.mysql.cj.jdbc.Driver”。
    4 driver-class-name: com.mysql.cj.jdbc.Driver
    5 #useSSL:SSL协议提供服务主要作用:(不建议在没有服务器身份验证的情况下建立SSL连接。)
    6 # 1)认证用户服务器,确保数据发送到正确的服务器;    .
    7 # 2)加密数据,防止数据传输途中被窃取使用;
    8 # 3)维护数据完整性,验证数据在传输过程中是否丢失;
    9 #serverTimezone:设置时区,不设置会报错。GMT%2B8:东八区北京时间 Asia/Shanghai:上海时间
    10 #useServerPrepStmts:在url中给出useServerPrepStmts=true参数,开启预编译(默认PS是关闭的)
    11 #allowMultiQueries:设置为true,开启批量执行sql的开关。更多请持续关注博主文档
    12 url: jdbc:mysql://localhost:3306/springboot?useSSL=false&serverTimezone=GMT%2B8
    13 username: root
    14 password: xsge
    15 #JPA配置——————————————————————————————————————————————————————————————————————————
    16 jpa:
    17 #是否显示SQL
    18 show-sql: true
    19 hibernate:
    20 #表结构处理方式方式。update表示,第一次执行时根据实体类创建表结构,之后的操作只做数据更新
    21 ddl-auto: update
  3. 新增实体类对应数据库表

    配置实体常用注解:(这里仅仅列举,更多详情请关注博主Hibernate文章)

    @Entity

    作用:标识当前实体为数据实体类

    @Table(name=值)

    作用:标识当前实体对应的是数据库表

    属性:Name:指定当前实体对应数据库表名称

    @Id

    作用:标识当前属性为主键列属性

    @Column

    作用:标识当前属性对应数据库的字段

    属性:Name:指定当前属性所对应的数据库字段列名称

    @GeneratedValue

    作用:指定字段列的主键策略

    属性:Generator:该属性值,指定Hibernate中提供的主键策略声明别名

      Strategy:该属性,标注JPA提供的主键生成策略(即主键生成方式)。

      取值GenerationType:

      AUTO:自适应,选择一下三种,默认选择TABLE

      IDENTITY:Mysql自增长,要判断是否支持

        SEQUENCE:Oracle自增长,要判断是否支持

       TABLE:类似于Helw高低位算法,无需判断,因为使用的是固定格式的算法生成。

     1 @Entity    // 标识当前实体为数据实体类
    2 @Data // 自动生成get/set等
    3 @AllArgsConstructor // 全参构造函数
    4 @NoArgsConstructor // 无参构造函数
    5 @Table(name = "student") // 标识实体对应的表名
    6 @EntityListeners(AuditingEntityListener.class) // spring-data-jap实体类数据更新的监听器注解
    7 public class Student {
    8 // 标识当前属性为主键列属性
    9 @Id
    10 // 标识字段列的主键策略(主键生成方式)GenerationType.IDENTITY表示shiyongMySQL默认自增长生成主键值
    11 @GeneratedValue(strategy = GenerationType.IDENTITY)
    12 private Integer sid;
    13
    14 // 标识当前属性对应数据库的字段
    15 @Column(name = "name")
    16 private String name;
    17 @Column(name = "age")
    18 private Integer age;
    19
    20 // spring-data-jap中提供的自动填充,新增时自动填充时间(配合SPRING-DATA-JPA监听注解使用)
    21 @CreatedDate
    22 private Date createTime;
    23
    24 // spring-data-jap中提供的自动填充,有更新时自动填充更新时间(配合SPING-DATA-JPA监听注解使用)
    25 @LastModifiedDate
    26 private Date updateTime;
    27 }

    这里需要注意,在《Mybatis-Plus使用全解》中,介绍过如何设置公共字段自动填充功能。比如创建时间和修改时间,创建人和修改人等等,都是可以一进行赋值的。在spring-data-jap中,是使用@CreatedDate@LastModifiedDate标记,同时,需要在实体类上,加@EntityListeners(AuditingEntityListener.class),然后在启动类上加入注解@EnableJpaAuditing(开启JPA自动填充),这样就实现类似公共字段自动填充的功能了。(JPA自动填充注解如下图)
    SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂)

  4. 修改SpringBoot主程序
    在启动类上加入注解@EnableJpaAuditing
     1 @SpringBootApplication
    2 @EnableJpaAuditing // 开启JPA自动填充功能
    3 @Slf4j
    4 public class AnnotaticSpringBootApplication {
    5 // 主函数
    6 public static void main(String[] args) {
    7 // 启动App
    8 SpringApplication.run(AnnotaticSpringBootApplication.class, args);
    9 log.info("主程序启动了………………");
    10 }
    11 }

2.整合实现CURD

  在Spring-Data-Jpa概述中,简单总结了JPA操作的方法,概括有三种:调用原接口方法实现简单CURD,自定义方法名实现简单CURD,自定义SQL实现CURD。通常情况下,三者结合使用,如果功能需求本身直接使用原接口方法就能实现那就无需更改,如果需求需要不同条件,那么自定义方法名即可,如果更为复杂的需求,直接使用自定义SQL实现。

A,接口源方法实现CURD

  1. 编写子接口继承接口JpaRepository。
    说明:JpaRepository接口中继承了来自各个父类的简单CURD方法,包括分页/排序等。这些方法可以直接引用,无需关注SQL。
    1 /**
    2 * 编写DAO接口继承JpaRepository接口
    3 * 泛型参数1:CURD实体类型
    4 * 泛型参数2:主键的类型(通常为Integer或Long)
    5 */
    6 public interface StudentDao extends JpaRepository<Student, Integer>{
    7 }
  2. 编写Service实现。
    (实际开发中需要抽象接口(Inteface)的不能省略,这里图方便就省略了,直接显示的是接口实现类)
    DAO对象直接自动注入即可,SpringBoot-Data-JPA自主扫描Repository及其所有子接口/子实现类组件。
    更多其他方法请自行参考附录
     1 @Service
    2 public class StudentServiceImpl implements StudentService {
    3
    4 @Autowired
    5 private StudentDao studentDao;
    6
    7 /**
    8 * 添加:调用JpaRepository的默认方法save实现保存
    9 * 返回值为添加的数据对象,同时还会将添加数据的id给返回
    10 */
    11 @Override
    12 public Student save(Student student) {
    13 return studentDao.save(student);
    14 }
    15 /**
    16 * 根据ID查询:调用JpaRepository的默认方法findById实现根据id查询
    17 * 返回结果为Optional<Student>,是JDK1.8新增的防null对象问题的一个核心类。
    18 * 你可以理解为将对象查询后,有放入到一个Optional容器中。调用方法get即可将对象取出
    19 */
    20 @Override
    21 public Student findById(Integer sid) {
    22 return studentDao.findById(sid).get();
    23 }
    24 /**
    25 * 分页查询:调用JpaRepository的默认方法findAll实现查询所有
    26 * 实际参数类型为:Pageable分页接口,PageRequest使其间接实现子类。
    27 * 参数1:当前页码(从0开始,不能为负数)
    28 * 参数2:当前页数据显示行数(从1开始,不能为负数)
    29 */
    30 @Override
    31 public Page<Student> findAll(Integer page,Integer size) {
    32 return studentDao.findAll(PageRequest.of(page,size));
    33 }
    34
    35 }
  3. 新增控制器,提供接口测试

     1 @RestController
    2 public class StudentController {
    3
    4 @Autowired
    5 private StudentService studentService;
    6
    7 /**
    8 * 测试接口:http://localhost:8080/saveStu
    9 * 请求方式:PUT 入参:JSON数据
    10 */
    11 @RequestMapping(value = "/saveStu",method = RequestMethod.PUT)
    12 public Student save(@RequestBody Student student) {
    13 return studentService.save(student);
    14 }
    15
    16 /**
    17 * 测试接口:http://localhost:8080/findById
    18 * 请求方式:GET 入参:占位符参数sid
    19 */
    20 @GetMapping("/findById/{id}")
    21 public Student findById(@PathVariable(name = "id") Integer sid) {
    22 return studentService.findById(sid);
    23 }
    24 /**
    25 * 测试接口:http://localhost:8080/findAll
    26 * 请求方式:POST 入参:page=?& size=?
    27 */
    28 @PostMapping("/findAll")
    29 public Page<Student> findAll(Integer page,Integer size) {
    30 return studentService.findAll(page,size);
    31 }
    32
    33 }
  4. 启动主程序,利用Postman工具测试
    SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂)

B,自定义方法名及自定义SQL实现操作

  当功能需求无法通过原接口方法能实现时,就需要手动自定义方法,或者自定义SQL实现CURD。其实并不需要多复杂的部署,在源方法案例的基础上,直接在持久层接口中新增自定义方法名的方法或者新增自定义SQL的方法即可。

 1 public interface StudentDao extends JpaRepository<Student, Integer>{
2 // 使用自定义命名方法名规则,进行查询服务,并添加分页功能
3 List<Student> findByNameContaining(String name,Pageable pageable);// …… where name like ‘%?%’
4
5 /**
6 * @Query进行 自定义sql编写
7 * nativeQuery=true:表示定义的SQL为标准SQL(没有这一项,SQL语句中的表名和字段名是实体类名和实体类中的字段名)
8 * 传参数使用占位符?代替,但需要注意的是这里的占位符后面需要跟数字(第几个?N 数字N从1开始)
9 */
10 @Query(value="select * from student where name = ?1",nativeQuery=true)
11 List<Student> queryByName(String name);
12 }

  其他测试省略……

附录

  JPA默认方法说明:查源码结构如下(内部方法好好看吧!)

1  QueryDslJpaRepository
2 ┣━ QueryDslPredicateExecutor
3 ┗━ SimpleJpaRepository
4 ┣━ JpaSpecificationExecutor
5 ┗━ JpaRepository
6 ┣━ QueryByExampleExecutor
7 ┗━ PagingAndSortingRepository
8 ┗━ CrudRepository
9 ┗━Repository