我一直在使用Mybatis做爲持久化框架,而且以爲Mybatis十分的不錯,足夠靈活,雖然說須要本身手寫sql,可是這也是我以爲的一個優勢,直觀而且優化方便.html
可是我以爲JPA規範也有其優勢,好比說簡單,在一些基本的CRUD操做時,徹底無需手寫SQL.java
所以趁着空閒,對Spring Data JPA作一個瞭解,並簡單的寫一個Demo來學習使用.mysql
在本文可能會涉及一下幾個概念,這裏統一講一下定義.web
JPA,即Java Persistence API.是Sun公司在Java EE 5規範中提出的Java持久化接口,即一種規範.spring
對象關係映射,即Object Relational Mapping,簡稱ORM.是一種程序技術,用於實現面向對象編程語言裏不一樣類型系統的數據之間的轉換.sql
Hibernate是一種ORM框架,Hibernate在3.2版本開始,已經徹底兼容JPA標準.數據庫
Mybatis是另一種ORM框架.使用它構建項目能夠看Spring Boot Mybatis Web 開發環境搭建編程
Spring Data JPA是Spring基於Hibernate開發的一個JPA框架,實現了JPA規範.segmentfault
前文說過,JPA的一個優勢就是不用寫簡單的CRUD的SQL語句,那麼怎麼作到的呢?mybatis
JPA能夠經過以下兩種方式指定查詢語句:
第一種功能基本能夠知足平常所需,當須要連表查詢或者一些更加複雜的操做時,可使用@Query
註解來使用本身編寫的sql進行查詢.
方法名和sql的對應關係在文末附錄
首先使用Spring Boot 及Maven搭建一個項目,這部分再也不贅述,有興趣能夠移步上面的連接.
在pox.xml中添加如下依賴,分別爲:
其中第四點爲我使用的鏈接池,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配置也沒有!!
首先在數據庫中建立表,本文測試表爲(在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
指定關聯的數據表.
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個接口,到底該繼承哪一個呢?
可是要說繼承哪一個接口呢?這個就見仁見智了,我是在不影響業務(主要是Crudrepository接口會提供刪除方法,有時候你並不想提供刪除)的狀況下,我通常使用JPARepository,畢竟功能比較全嘛.
在今天的學習後,對Jpa也算是有一點了解,在我看來,他和Mysql是兩種不一樣的思路,可是均可以完成同一個任務.
在業務邏輯較爲簡單的時候,使用JPA能夠提升開發效率,由於基本的增刪改查你連方法定義都不須要寫.....而後大部分較簡單的查詢你均可以經過定義方法名來完成,實在不行還有@Query
手寫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) |
www.ibm.com/developerwo… segmentfault.com/a/119000000…
完。
以上皆爲我的所思所得,若有錯誤歡迎評論區指正。
歡迎轉載,煩請署名並保留原文連接。
聯繫郵箱:huyanshi2580@gmail.com
更多學習筆記見我的博客------>呼延十