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 @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