SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂)
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
&n