1. 程式人生 > >SpringBoot第四集:整合JdbcTemplate和JPA(2020最新最易懂)

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. 建立資料庫。
  2. 新增對應資料庫實體類。
    1 @Data
    2 @AllArgsConstructor
    3 @NoArgsConstructor
    4 public class Person {
    5     private Integer id;
    6     private String name;
    7     private String password;
    8 }
  3. 修改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>
  4. 修改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.整合實現

  1. 編寫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 }
  2. 編寫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 }
  3. 編寫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 }
  4. 編寫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 }
  5. 安裝Postman工具,訪問測試介面。
    啟動SpirngBoot專案主程式,請求介面測試!
    Postman是一款常用的介面測試工具,可以測試傳送不同請求,傳遞不同引數,具體操作請關注博主盡情期待。PostMan下載地址

 

二.整合JPA

  JPA是Java Persistence API的簡稱,中文名Java持久層API。是SUN公司推出的一套基於ORM的規範。Hibernate框架中提供了JPA的實現,Spring Data JPASpring基於Hibernate開發的一個JPA框架。可以極大的簡化JPA的寫法,可以在幾乎不用寫具體程式碼的情況下,實現對資料的訪問和操作。除了CRUD外,還包括如分頁排序等一些常用的功能。此外更強大的是,它還可以通過方法命名規則進行資料庫查詢操作

  Spring Data JPA提供的介面:

  1. Repository:最頂層的介面,是一個空的介面,目的是為了統一所有Repository的型別,且能讓元件掃描的時候自動識別。
  2. CrudRepository :是Repository的子介面,提供CRUD的功能(內建預設的簡單的CURD方法,可以直接引用)
  3. PagingAndSortingRepository:是CrudRepository的子介面,新增分頁和排序的功能。
  4. JpaRepository:是PagingAndSortingRepository的子介面,增加了一些實用的功能,比如:批量操作等。(相對最完整的內建方法:簡單的CURD/分頁/批量)
  5. JpaSpecificationExecutor:用來做負責查詢的介面
  6. 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簡單總結:

  1. 提供了基本的CURD方法,批處理,分頁方法等。
  2. 允許自定義方法名,根據指定命名規則實現查詢。
  3. 允許使用@Query註解,自定義更高階,更復雜的SQL

1.準備工作

  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>
  2. 修改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
  3. 新增實體類對應資料庫表

    配置實體常用註解:(這裡僅僅列舉,更多詳情請關注博主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自動填充註解如下圖)

  4. 修改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

  1. 編寫子介面繼承介面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 }
  2. 編寫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 }
  3. 新增控制器,提供介面測試

     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 }
  4. 啟動主程式,利用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