SpringBoot第四集:整合JDBC,JdbcTemplate,JPA(2021最新最易懂)
當前環境說明:
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