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);
}
}