前言: 之前總結了 Spring Boot 入門相關的博文,後端開發自然離不開對數據庫的操作,所以今天來對數據庫操作進行總結。由於剛入門,選擇一種使用簡單的組件——Jpa。簡單到我們不需要寫一句 sql 語句。
下面引用官網對 Spring-Data-Jpa 的介紹:
Spring Data JPA 是 Spring Data 系列的一部分,可以輕鬆實現基於 JPA 的存儲庫。 該模塊處理對基於 JPA 的數據訪問層的增強的支持。 這使得使用數據訪問技術構建Spring 的應用程序變得更加容易。
如果我們使用原生 JDBC 的方式來訪問數據庫,那麼我們必須編寫太多的樣板代碼。開發效率明顯降低,Jpa 則定義了對象關係映射以及實體對象持久化的標準接口,也就是 ORM 框架,相信做過 Java /android 的 oop 編程的人都或多或少的接觸過,以面向對象的方式來操作數據庫,Spring Data JPA 則在基於 JPA 進一步簡化了數據訪問層的實現,它提供了一種類似於聲明式編程的方式,開發者只需要編寫數據訪問接口(稱爲Repository),Spring Data JPA 就能基於接口中的方法命名自動地生成實現。
廢話就到這了,注意正式開始使用之前,本地必須裝有數據庫,以及對數據庫基本操作有一定的瞭解,這裏我使用的是 MySql 數據庫,安裝過程請自行 google ,使用可以參考鏈接:mysql基本操作命令彙總--筆記
一、 首先添加依賴
<dependency>
<!--下載所有Spring Data Jpa所需的依賴-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<!--我們的數據庫是mysql,所以還需要mysql-connector-java依賴-->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
二、數據源配置
在配置文件 application.properties
中添加配置
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/db_users
spring.datasource.username=root//配置數據庫賬號
spring.datasource.password=root//配置數據庫密碼
spring.datasource.driver-class-name=com.mysql.jdbc.Driver//配置MySql驅動
配置解析:
spring.datasource.url
:配置本地數據庫訪問地址,默認端口3306,數據庫名:db_users
spring.jpa.show-sql
:設置爲 true,當我們操作數據庫時,會在控制檯顯示出我們操作對應的 sql 語句,false 則不行。spring.jpa.hibernate.ddl-auto
:設置爲update
,當我們更新數據庫的時候,不會刪除舊錶,如果使用create
,更新數據庫時,會刪除舊錶重建,會造成數據丟失。
就這樣配置就可以操作數據庫了,當然還有更多的配置可以參考下官方文檔,我們只需要關注 以spring.datasource
,spring.jpa
開頭的即可。
三、創建數據表
前面我們說了 Jpa 是 orm 映射型框架。只要我們聲明實體類,實體類中的字段就會映射到數據庫中自動生成數據表。
新建 User
類:
@Entity//自動映射數據表
public class User {
//id自增
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String username;
@Column
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
.......此處省略set get方法
}
分析:User 類包含三個字段:
- id作爲唯一標識符,
@GeneratedValue(strategy=GenerationType.AUTO)
表明id是一個自增字段。 username
和password
爲普通字段,@Column註解
可有可無@Entity註解
:標記在類上,當程序運行,User 類會自動映射到數據庫中,生成以User
名的數據表,User 類的字段自動映射爲數據表的字段。@Table(name = {數據表名})
:可有可無,如果我們不喜歡默認用類名作爲數據表名,可以使用註解自定義數據表名
運行項目,此時不出意外,服務器啓動成功會自動生成```user``數據表
數據表.png
命令行查看,user
數據表已經創建成功~
四、數據表增刪改查操作
前面我們提到 Spring-Data-Jpa 提供了一種類似於聲明式編程的方式,開發者只需要編寫數據訪問接口(稱爲Repository),Spring Data JPA就能基於接口中的方法命名自動地生成實現。
定義 UserRepository
接口,繼承JpaRepository
,此接口是 Spring-Data-Jpa 內部定義好的泛型接口,第一個參數實體類,第二個參數是ID。已經幫我們實現了基本的增刪改查的功能,現在只要持有 UserRepository
就能操作數據表,哈哈~就是如此神奇。。
public interface UserRepository extends JpaRepository<User,Long>{
}
源碼分析:進入源碼查看接口的繼承結構發現 JpaRepository
繼承自PagingAndSortingRepository
繼承自CrudRepository
繼承自Repository
Repository
:泛型接口,第一個參數是實體類,第二個參數是實體類ID
,最頂層接口,不包含任何方法,目的是爲了統一所有的Repository
的類型,且能讓組件掃描的時候自動識別。
public interface Repository<T, ID extends Serializable> {
}
CrudRepository
:Repository
的子接口,封裝數據表的 CRUD 方法。
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S var1);//存儲一條數據實體
<S extends T> Iterable<S> save(Iterable<S> var1);//批量存儲數據
T findOne(ID var1);//根據id查詢一條數據實體
boolean exists(ID var1);//判斷指定id是否存在
Iterable<T> findAll();//查詢所有的數據
Iterable<T> findAll(Iterable<ID> var1);//根據一組id批量查詢實體
long count();//返回數據的條數
void delete(ID var1);//根據id刪除數據
void delete(T var1);//刪除數據
void delete(Iterable<? extends T> var1);//批量刪除數據
void deleteAll();//刪除所有數據
}
PagingAndSortingRepository
:CrudRepository
的子接口,擴展了分頁和排序功能。
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort var1);//根據某個排序獲取所有數據
Page<T> findAll(Pageable var1);//根據分頁信息獲取某一頁的數據
}
JpaRepository
:PagingAndSortingRepository
的子接口,增加一些實用的功能, 如批量操作
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
List<T> findAll(); //獲取所有數據,以List的方式返回
List<T> findAll(Sort var1); //根據某個排序獲取所有數據,以List的方式返回
List<T> findAll(Iterable<ID> var1); //根據一組id返回對應的對象,以List的方式返回
<S extends T> List<S> save(Iterable<S> var1); //將一組對象持久化到數據庫中,以List的方式返回
void flush(); //將修改更新到數據庫
<S extends T> S saveAndFlush(S var1); //保存數據並將修改更新到數據庫
void deleteInBatch(Iterable<T> var1); //批量刪除數據
void deleteAllInBatch(); //批量刪除所有數據
T getOne(ID var1); //根據id查找並返回一個對象
}
五、實際應用
定義完接口之後,只要拿到接口引用,我們就能輕鬆完成基本的數據表操作了,現在來試試寫幾個 url 接口玩玩,體驗一下。寫接口之前建議先看下文章 Spring Boot 學習總結之 Controller 註解
- 將
UserRepository
引用注入UserController
,編寫POST
請求的 url 接口,提交一條表單數據保存到數據表中。
@RestController//處理http請求,返回json格式
@RequestMapping(value = "/users")//配置url,讓該類下的所有接口url都映射在/users下
public class UserController {
@Autowired//注入實例
UserRepository userRepository;
@PostMapping(value = "/save")
public User saveUser(@RequestParam(value = "username", required = false, defaultValue = "張少林") String username,
@RequestParam(value = "password", required = false, defaultValue = "123456") String password) {
User user = new User(username, password);
return userRepository.save(user);//保存數據到數據表中,並返回
}
}
此時 url 接口地址可以爲:http://127.0.0.1:8080/users/save?username=張少林&password=123456
,請求方法:post
,結果在界面上顯示 json 格式數據:
插入數據.png
查看數據表 數據已經存入成功:
插入一條數據.png
- 我們手動往數據表中添加三條數據,測試一下 查詢方法
編寫查詢所有用戶數據 url 接口
@GetMapping(value = "/all")
public List<User> findAll() {
return userRepository.findAll();//查詢所有數據並返回
}
url 接口地址:http://127.0.0.1:8080/users/all
請求方法 :GET
,結果如下
查詢所有數據.png
注意:實體類 User 必須添加空構造方法,否則這裏查詢會報錯
其他的方法就不一一舉例了,按照上面源碼中的方法依葫蘆畫瓢就能操作數據表了。那麼問題來了,Jpa 內部只幫我們實現了簡單的 Crud
方法,那麼遇到較爲複雜自定義條件查詢操作咋辦呢?,這時候就要用到 Spring-Data 的內建查詢機制了。
六、內建查詢機制
Spring Data 會識別出find...By
, read...By
和get...By
這樣的前綴,從後面的命名中解析出查詢的條件。方法命名的的第一個By
表示查詢條件的開始,多個條件可以通過And
和Or
來連接。
舉個栗子哈.jpg
在 UserRepository
中聲明查詢方法:
public interface UserRepository extends JpaRepository<User, Long> {
/**
* \根據用戶名批量查詢用戶數據
*
* @param username
* @return
*/
List<User> findByUsername(String username);
}
就是如此簡單,只需要在接口中聲明對應的查詢方法,不需要去實現它,Spring-Data-Jpa 會根據方法名幫我們智能解析爲 sql 語句,並且執行查詢。
測試:數據庫中再手動添加兩條相同用戶數據,編寫 url 請求接口
@GetMapping(value = "/findByUsername")
public List<User> findByUsername(@RequestParam(value = "username", required = false,
defaultValue = "張少林") String username) {
return userRepository.findByUsername(username);//根據用戶名批量查詢用戶數據
}
配置 url
地址 返回結果爲:
根據用戶名查詢.png
可以看到控制檯打印了 sql 語句:
sql語句.png
這也印證了我們之前的觀點, Spring-Data-Jpa 自動根據方法名智能幫我們解析 sql 語句並執行查詢功能。
除了And
和Or
,表示查詢條件的屬性表達式中還可以通過Between
、LessThan
、GreaterThan
和Like
等操作符。 可以使用IngoreCase
來忽略屬性的大小寫,也可以使用AllIgnoreCase
來忽略全部屬性的大小寫。
可以使用OrderBy
來進行排序查詢,排序的方向是Asc
跟Desc
。
Spring-Data 爲我們提供的關鍵字見下面表格:
關鍵字 | 例子 | 對應的JPQL語句 |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
結語:至此,
Spring-Data-Jpa
的基本使用總結先告一段落了,雖然還有很多東西沒涉及到,但是基於此,再結合 Spring Boot 學習總結之 Controller 註解 我們寫簡單的後臺 json 數據接口已經沒啥問題了。