SpringBoot第四集:整合JDBC,JdbcTemplate,JPA(2020最新最易懂)
当前环境说明:
Windows10_64
Maven3.x
JDK1.8
MySQL5.6
SpringToolSuite4(Spring官方提供的开发工具,实际就是一个Eclipse)
一.整合JDBC
对于数据访问层,无论是SQL(关系型数据库)还是NOSQL(非关系型数据库),Spring Boot底层都是采用Spring Data的方式进行统一处理。 Spring Data也是Spring中与Spring Boot,Spring Cloud等齐名的知名项目。并且Spring Data中内置连接池数据源HikariDataSource,HikariDataSource号称Java WEB当前速度最快的数据源,相比于传统的C3P0、DBCP、Druid、TomcatJDBC等连接池更加优秀;Spring Data允许开发者自主选择数据源。
访问SpringBoot官网,可以查看Spring Data的支持,获取Spring Data启动器依赖。
1.SpringBoot实现JDBC整合
实现JDBC整合,使用SpringData默认连接池数据源
- 新建SpringBoot项目,选择依赖
1 <!-- SpringBoot整合JDBC --> 2 <dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-jdbc</artifactId> 5 </dependency> 6 <!-- MySQL驱动:默认8.x,如果你使用的MySQL版本较低,且手动切换版本 --> 7 <dependency> 8 <groupId>mysql</groupId> 9 <artifactId>mysql-connector-java</artifactId> 10 <scope>runtime</scope> 11 </dependency>
- 修改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?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8 13 username: root 14 password: xsge
- 新建测试类,获取JDBC链接对象和池对象
获取JDBC链接对象后,就可以实现CURD了。
1 @SpringBootTest 2 class SpringbootJdbcApplicationTests { 3 @Autowired 4 DataSource dataSource;// 自动注入链接池数据源对象 5 @Test 6 void contextLoads() throws Exception { 7 Connection connection = dataSource.getConnection(); 8 System.out.println("数据源:"+dataSource); 9 System.out.println("链接对象:"+connection); 10 } 11 12 }
- 运行查看控制台结果
1 数据源:HikariDataSource (HikariPool-1) 2 链接对象:HikariProxyConnection@1886247880 wrapping com.mysql.cj.jdbc.ConnectionImpl@fd09e43
就这???都框架整合了,难道以后使用原始JDBC写CURD ?这里主要是介绍Spring Data内部的默认集成数据源,且Spring Data也提供了很多CURD工具支持,例如:JPA,JdbcTemplate等。
二.整合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 @Data 2 @AllArgsConstructor 3 @NoArgsConstructor 4 public class Person { 5 private Integer id; 6 private String name; 7 private String password; 8 }
- 修改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>
- 修改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.整合实现
- 编写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 }
- 编写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 }
- 编写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 }
- 编写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 }
- 安装Postman工具,访问测试接口。
启动SpirngBoot项目主程序,请求接口测试!
Postman是一款常用的接口测试工具,可以测试发送不同请求,传递不同参数,具体操作请关注博主尽情期待。PostMan下载地址
三.整合JPA
JPA是Java Persistence API的简称,中文名Java持久层API。是SUN公司推出的一套基于ORM的规范。Hibernate框架中提供了JPA的实现,Spring Data JPA
是Spring
基于Hibernate
开发的一个JPA
框架。可以极大的简化JPA
的写法,可以在几乎不用写具体代码的情况下,实现对数据的访问和操作。除了CRUD
外,还包括如分页
、排序
等一些常用的功能。此外更强大的是,它还可以通过方法命名规则
进行数据库查询操作
Spring Data JPA提供的接口:
Repository
:最顶层的接口,是一个空的接口,目的是为了统一所有Repository的类型,且能让组件扫描的时候自动识别。CrudRepository
:是Repository的子接口,提供CRUD的功能(内置默认的简单的CURD方法,可以直接引用)PagingAndSortingRepository
:是CrudRepository的子接口,添加分页和排序的功能。JpaRepository
:是PagingAndSortingRepository的子接口,增加了一些实用的功能,比如:批量操作等。(相对最完整的内置方法:简单的CURD/分页/批量)JpaSpecificationExecutor
:用来做负责查询的接口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简单总结:
- 提供了基本的CURD方法,批处理,分页方法等。
- 允许自定义方法名,根据指定命名规则实现查询。
- 允许使用@Query注解,自定义更高级,更复杂的SQL
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>
- 修改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
- 新增实体类对应数据库表
配置实体常用注解:(这里仅仅列举,更多详情请关注博主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主程序
在启动类上加入注解@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
- 编写子接口继承接口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 }
- 编写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 }
- 新增控制器,提供接口测试
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 }
- 启动主程序,利用Postman工具测试
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