前言
我一直在使用Mybatis作爲持久化框架,並且覺得Mybatis十分的不錯,足夠靈活,雖說需要自己手寫sql,但是這也是我覺得的一個優點,直觀並且優化方便.
但是我覺得JPA規範也有其優點,比如說簡單,在一些基本的CRUD操作時,完全無需手寫SQL.
因此趁着空閒,對Spring Data JPA做一個瞭解,並簡單的寫一個Demo來學習使用.
定義
在本文可能會涉及一下幾個概念,這裏統一講一下定義.
JPA
JPA,即Java Persistence API.是Sun公司在Java EE 5規範中提出的Java持久化接口,即一種規範.
ORM
對象關係映射,即Object Relational Mapping,簡稱ORM.是一種程序技術,用於實現面向對象編程語言裏不同類型系統的數據之間的轉換.
Hibernate
Hibernate是一種ORM框架,Hibernate在3.2版本開始,已經完全兼容JPA標準.
Mybatis
Mybatis是另外一種ORM框架.使用它構建項目可以看Spring Boot Mybatis Web 開發環境搭建
Spring Data JPA
Spring Data JPA是Spring基於Hibernate開發的一個JPA框架,實現了JPA規範.
Spring Data JPA 實現原理
前文說過,JPA的一個優點就是不用寫簡單的CRUD的SQL語句,那麼怎麼做到的呢?
JPA可以通過如下兩種方式指定查詢語句:
- Spring Data JPA 可以訪問 JPA 命名查詢語句。開發者只需要在定義命名查詢語句時,爲其指定一個符合給定格式的名字,Spring Data JPA 便會在創建代理對象時,使用該命名查詢語句來實現其功能。
- 開發者還可以直接在聲明的方法上面使用 @Query 註解,並提供一個查詢語句作爲參數,Spring Data JPA 在創建代理對象時,便以提供的查詢語句來實現其功能。
第一種功能基本可以滿足日常所需,當需要連表查詢或者一些更加複雜的操作時,可以使用@Query
註解來使用自己編寫的sql進行查詢.
方法名和sql的對應關係在文末附錄
環境搭建
首先使用Spring Boot 及Maven搭建一個項目,這部分不再贅述,有興趣可以移步上面的鏈接.
添加依賴
在pox.xml中添加以下依賴,分別爲:
- spring-data-jpa
- Hibernate-core
- Hibernate–annotations
- HikariCP
其中第四點爲我使用的連接池,Spring Boot官方也比較推薦這個,當然,可以換成C3P0或者其他連接池.
<!-- spring-data-jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.7.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-annotations -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.5.6-Final</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.2.0</version>
</dependency>
配置文件
在application.yaml
文件中加入以下內容,設置服務啓動端口,使用配置爲local
以及數據源的一些配置,最後是JPA的配置.
server:
port: 9999
spring:
profiles:
active: local
datasource:
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 0
initial-size: 5
maximum-pool-size: 15
auto-commit: true
pool-name: NezhaHikariCP
test-connection-on-checkout: true
jpa:
database: MYSQL
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
同時,新建application-local.yaml
中加入以下內容,設置mysql數據源的相關信息.
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1/test?characterEncoding=utf8&useSSL=false
username: root
password: root
jpa:
show-sql: true
環境的搭建就是上面那麼簡單,第一步添加依賴,第二步添加一些配置就ok.
剩下的就是編寫一些業務代碼,而各種配置類什麼的完全沒有!!XML配置也沒有!!
Demo創建
創建數據表
首先在數據庫中創建表,本文測試表爲(在test數據庫中):
mysql> desc student;
+------------+-------------+------+-----+---------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------------------+-----------------------------+
| id | int(10) | NO | | NULL | |
| name | varchar(45) | NO | PRI | NULL | |
| class_num | int(12) | YES | | NULL | |
| age | int(3) | YES | | 18 | |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | |
| updated_at | timestamp | NO | | 2018-01-01 00:00:00 | on update CURRENT_TIMESTAMP |
+------------+-------------+------+-----+---------------------+-----------------------------+
6 rows in set (0.01 sec)
建表語句爲:
CREATE TABLE `student` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(45) NOT NULL COMMENT '姓名',
`class_num` int(12) DEFAULT NULL COMMENT '班級',
`age` int(3) DEFAULT '18' COMMENT '年齡',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
`updated_at` timestamp NOT NULL DEFAULT '2018-01-01 00:00:00' ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
創建實體類
在model包下創建Student
實體類:
package com.huyan.demo.model;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* created by huyanshi on 2018/12/21
*/
@AllArgsConstructor
@Builder
@Data
@NoArgsConstructor
@Entity
@Table(name = "student")
public class Student {
@Id
private int id;
private String name;
private int classNum;
private int age;
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
@Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
}
其中,@Entity
標識此類是一個實體類,@Table
指定關聯的數據表.
創建dao層接口
package com.huyan.demo.dao;
import com.huyan.demo.model.Student;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* created by huyanshi on 2018/12/21
*/
@Repository
public interface StudentDao extends JpaRepository<Student,String> {
List<Student> findAll();
}
在接口上打上@Repository
註解並實現JpaRepository接口.該接口使用了泛型,需要爲其提供兩個類型:第一個爲該接口處理的域對象類型,第二個爲該域對象的主鍵類型
好,demo到此就結束了,service層和controller隨意寫,只要調用List<Student> findAll();
這個方法,就會查找該表格中的所有數據.
我寫了個很簡單的接口,直接返回拿到的list,數據結果集爲:
注意,在這個過程中,我們是沒有手寫SQL的,如果是在使用mybatis的過程中,我們需要編寫select * from student
的SQL語句.
更多方法示例
費勁搞了JPA,當然不可寫一個方法就完事了.這樣在實際應用中沒有多少幫助.因此,我將一些常用的方法類型
在這裏測試一遍使用方法,最後,將其整合輸出.
實際測試我才發現,許多的方法在繼承的接口中早已定義,比如查詢全量,根據主鍵嗯增刪改查,排序,分頁等,可謂十分強大,因此簡單測試了大於小於及多參數的查詢.
以下代碼實際運行通過.
@Repository
public interface StudentDao extends JpaRepository<Student, Integer> {
//查詢所有
List<Student> findAll();
//查詢年齡大於傳入值得
List<Student> findByAgeAfter(int age);
//查詢年齡和班級等於入參的
List<Student> findByAgeAndClassNum(int age, int classNum);
//查詢年齡爲入參的學生,且結果按照創建時間排序
List<Student> findByAgeOrderByCreatedAt(int age);
//根據主鍵更新實體的名字年齡及班級
@Modifying(clearAutomatically = true)
@Transactional
@Query(value = "UPDATE Student SET name = :name, classNum = :classNum, "
+ "age = :age WHERE id = :id ")
int updateNameAndAgeAndClassNumById(@Param("name") String name, @Param("age") int age,
@Param("classNum") int classNum, @Param("id") int id);
}
繼承哪個接口
在上文中創建dao層接口
中,我們要繼承Repository
接口,但是在Spring Data JPA中,提供了4個接口,到底該繼承哪個呢?
- Repository接口,沒有定義方法.
- CrudRepository接口,繼承自Repository接口,定義了基本的增刪改查.
- PagingAndSortingRepository接口,繼承自CrudRepository接口,定義了排序及分頁方法.
- JpaRepository接口,繼承自PagingAndSortingRepository接口,提供了 flush(),saveAndFlush(),deleteInBatch() 等方法.
但是要說繼承哪個接口呢?這個就見仁見智了,我是在不影響業務(主要是Crudrepository接口會提供刪除方法,有時候你並不想提供刪除)的情況下,我一般使用JPARepository,畢竟功能比較全嘛.
後話
在今天的學習後,對Jpa也算是有一點了解,在我看來,他和Mysql是兩種不同的思路,但是都可以完成同一個任務.
在業務邏輯較爲簡單的時候,使用JPA可以提高開發效率,因爲基本的增刪改查你連方法定義都不需要寫…然後大部分較簡單的查詢你都可以通過定義方法名來完成,實在不行還有@Query
手寫sql兜底.
附錄:方法關鍵字和使用方式及生成的SQL列表
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | 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<Age> ages)</Age> | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<Age> age)</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) |
參考鏈接
https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-jpa/index.html
https://segmentfault.com/a/1190000009866465
完。
ChangeLog
2018-12-22 完成以上皆爲個人所思所得,如有錯誤歡迎評論區指正。
歡迎轉載,煩請署名並保留原文鏈接。
聯繫郵箱:[email protected]
更多學習筆記見個人博客------>呼延十