SpringBoot提供的数据持久层的解决方案:
- SpringBoot+jdbctemplate(用的很少,自己demo用用挺好,轻量级,功能比较少)
- SpringBoot+MyBatis(实际开发中使用最多)
- SpringBoot+Spring Date JPA(没有2用的多,它的优点可能就在于它是Spring整个体系下提供的,并且支持ORM,因为底层基于Hibernate实现的,自动完成实体类和表的映射,就不用像MyBatis那样手动完成映射了。)
概念
1.Hibernate:Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。属于全自动的ORM框架,着力点在于POJO和数据库表之间的映射,完成映射即可自动生成和执行sql。
2.Mybatis:MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。属于半自动的ORM框架,着力点在于POJO和SQL之间的映射,自己编写sql语句,然后通过配置文件将所需的参数和返回的字段映射到POJO。
3.Spring Data JPA:Spring Data是一个通过命名规范简化数据库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务。
1.SpringBoot+jdbctemplate
JdbcTemplate 是 Spring 自带的 JDBC 模版组件,底层实现了对 JDBC 的封装,⽤用法与 MyBatis 类似,开发者需要⾃自定义 SQL 语句句,JdbcTemplate 帮助开发者完成数据库连接,SQL 执⾏,以及结果集的解析。
目录结构:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.southwind</groupId>
<artifactId>jdbctemplate</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
entity:
@Data
public class Student {
private int id;
private String name;
}
数据层:
public interface StudentRepository {
Student findById(int id);
}
@Repository
public class StudengRepositoryImpl implements StudentRepository {
@Autowired
JdbcTemplate jdbcTemplate;
@Override
public Student findById(int id) {
//三个参数:1.sql。2.参数数组。3.BeanPropertyRowMapper是RowMapper的实现类。RowMapper是一个接口,作用是解析结果集,将sql查询出的ResultSet对象转换为泛型指定的java对象。
return jdbcTemplate.queryForObject("select * from student where id = ?",new Object[]{id},new BeanPropertyRowMapper<Student>(Student.class));
}
}
controller层:
@RestController
public class StudentHandler {
@Autowired
StudentRepository studentRepository;
@GetMapping("/findById/{id}")
public Student findById(@PathVariable("id") int id){
return studentRepository.findById(id);
}
}
Application启动类:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
配置文件:
spring:
datasource:
url: jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC
username: root
password: xxxx
driver-class-name: com.mysql.cj.jdbc.Driver
数据库部分就建了个Student表。
上面代码复制即可运行。
因为jdbc现实中很少使用的,所以就curd就不具体写了。
可以注意的是:
JdbcTemplate 对基本的 CRUD 操作提供了了良好的⽀支持,通过调⽤用 query 和 update ⽅方法即完成相关操作,其中 query 是⽤用来做查询操作的,update 是⽤用来做添加、删除、修改功能。
1、queryForObject(String sql,Object[] args,RowMapper rowMapper),查询⼀条记录,并且将结果集封装成 Java 对象。
2、query(String sql,RowMapper rowMapper),查询⼀组数据,并且将结果集封装成集合对象。RowMapper 是⼀个接⼝,作⽤就是解析结果集,将 JDBC 查询出的 ResultSet 对象转换为对应的 Java对象,在调⽤用该对象时需要指定目标类的结构,泛型。
update(String sql, Object… args)
参数:1、要执⾏的 SQL 语句。2、可变参数 Object…args,满⾜参数的可变性。
客户端⽤?传参 key-value 形式将数据传给 Spring MVC 服务端,业务方法的形参列表不需要添加任何注解即可自动封装参数 Java 对象。
客户端传 JSON 格式数据,业务⽅法的形参列表需要添加 @RequestBody 注解,才能封装参数 Java 对象。
业务方法的参数的注解形式比较:
@PathVariable:
@GetMapping("/findById/{id}")
public Student findById(@PathVariable("id") int id){
return studentRepository.findById(id);
}
访问服务的url格式:http://localhost:8080/findById/1
@RequestParam:
@GetMapping("/findById")
public Student findById(@RequestParam int id){
return studentRepository.findById(id);
}
访问服务的url格式:http://localhost:8080/findById?id=1,当然@RequestParam:是可以省略的!
@RequestBody:
@GetMapping("/saveByStu")
public Student findById(@RequestBody Student stu){
return studentRepository.findById(stu);
}
访问服务的url格式:http://localhost:8080/saveByStu,我是用postman测试的,传入josn格式的数据。如果不写这个注解,是数据添加不进去的。因为参数压根就没有解析拿到。
2.SpringBoot+MyBatis
目录结构:
与jdbcTemplate相比,MyBatis主要区别在于不用再java中写sql语句,而是用xml语句完成,灵活性和扩展性更好。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>www.gosang</groupId>
<artifactId>springbootMyBatis</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
username: root
password: xxxx
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: /mapping/*.xml
type-aliases-package: com.gosang.entity
配置了实体类和mapping的映射。
Application
package com.gosang;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.gosang.repository")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
启动类与jdbc不同的是加了@MapperScan(“com.gosang.repository”),扫描,把这些代理类交给Spring管理。
其他的业务代码就大差不差了。如下:
StudentRepository.java
public interface StudentRepository {
List<Student> findAll();
Student findById(int id);
void save(Student student);
void update(Student student);
void delete(int id);
}
StudentRepository.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gosang.repository.StudentRepository">
<select id="findAll" resultType="Student">
select * from student
</select>
<select id = "findById" parameterType = "int" resultType = "Student">
select * from Student where id = #{id}
</select>
<insert id="save" parameterType="Student">
insert into Student(name) VALUES (#{name});
</insert>
<update id="update" parameterType="Student">
update Student set name = #{name} where id = #{id}
</update>
<delete id="delete" parameterType="int">
delete from Student where id = #{id}
</delete>
</mapper>
StudentHandler.java
@RestController
public class StudentHandler {
@Autowired
StudentRepository studentRepository;
@GetMapping("/findAll")
public List<Student> fingAll(){
return studentRepository.findAll();
}
@GetMapping("/findById")
public Student findById(int id){
return studentRepository.findById(id);
}
@PostMapping("/save")
public void save(@RequestBody Student student){
studentRepository.save(student);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
studentRepository.update(student);
}
@DeleteMapping("/delete")
public void delete(int id){
studentRepository.delete(id);
}
}
同上在postman中去测试。
http://localhost:8080/findAll
http://localhost:8080/findById?id=1
**小结:**与jdbc那种在java文件中写sql式的硬编码方式相比MyBatis就显得更加灵活,耦合度更低。
3.SpringBoot+Spring Date JPA
Spring Date JPA是Spring提供的持久层解决方案,但它本身并不是一个具体的实现,它是比较上层的封装,底层还是基于Hibernate。
虽然JdbcTemplate同样是Spring提供的,但他只是一个模板。Spring Date JPA是一个体系更大的基于Hibernate的持久层实现。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.southwind</groupId>
<artifactId>springboot+springdatajpa</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: xxx
url: jdbc:mysql://localhost:3306/mybatis
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
Application
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
entity实体类
@Data
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String name;
}
这里实体类的写法就和前两种有所区别了。能自动完成映射这些注解少不了。
StudentRepository
public interface StudentRepository extends JpaRepository<Student,Long> {
public Student findByName(String name);
}
用这个方案和Hibernate一样,连sql语句都不用写了,都是JpaRepository会提供的。我们只要继承这个接口就可以使用的,开箱即用。要注意的是,起名字一定要规范,才能自动识别到对应类型的sql。如public Student findByName(String name);。
StudentHandler
@RestController
public class StudentHandler {
@Autowired
private StudentRepository studentRepository;
@GetMapping("/findAll")
public List<Student> findAll(){
return studentRepository.findAll();
}
@GetMapping("/findById/{id}")
public Student findById(@PathVariable("id") Long id){
return studentRepository.findById(id).get();
}
@PostMapping("/save")
public void save(@RequestBody Student student){
studentRepository.save(student);
}
@PutMapping("/update")
public void update(@RequestBody Student student){
studentRepository.save(student);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") Long id){
studentRepository.deleteById(id);
}
@GetMapping("/findByName/{name}")
public Student findByName(@PathVariable("name") String name){
return studentRepository.findByName(name);
}
}