springboot+jpa 整合與基本應用
springboot+jpa 整合與基本應用
什麼是jpa
JPA (The Java Persistence API)是用於訪問,持久化和管理 Java 物件/類與關係型資料庫之間的資料互動的 Java 規範。JPA 被定義為EJB (Enterprise JavaBeans) 3.0規範的一部分,作為 EJB 2 CMP 實體 Bean 規範的替代。
注意,JPA 只是一個標準,只定義了一系列介面,而沒有具體的實現。很多企業級框架提供了對 JPA 的實現,如 Spring 。因此 Spring 本身與 JPA 無關,只是提供了對 JPA 的支援,因此在 Spring 中你也會看到很多註解都是屬於 javax.persistence 包的。
JPA 允許 POJO(Plain Old Java Objects)輕鬆地持久化,而不需要類來實現 EJB 2 CM P規範所需的任何介面或方法。 JPA 還允許通過註解或 XML 定義物件的關係對映,定義 Java 類如何對映到關係資料庫表。 JPA 還定義了一個執行時 EntityManager API,用於處理物件的查詢和管理事務。 同時,JPA 定義了物件級查詢語言 JPQL,以允許從資料庫中查詢物件,實現了對資料庫的解耦合,提高了程式的可移植性,而不具體依賴某一底層資料庫。
JPA 是 Java 持久化規範中的一個最新版本。第一個版本是 OMG 永續性服務 Java 繫結,但這個一個失敗的產品,甚至沒有任何商業產品支援它。接下來的版本是 EJB 1.0 CMP Entity Beans,它已經非常成功地被大型 Java EE 提供程式(BEA,IBM)採用,但是它複雜性太高而且效能比較差。EJB 2.0 CMP 試圖通過引入本地介面來減少 Entity Bean 的一些複雜性,但是大多數複雜性仍然存在,而且缺乏可移植性。
歷史總是要向前發展的,種種的這些使得 EJB 3.0 規範將降低複雜性作為主要目標,這導致規範委員會沿著 JPA 的路徑前進。 JPA 旨在統一 EJB 2 CMP,JDO,Hibernate,從目前來看,JPA 的確取得了成功。
目前大多數持久化供應商已經發布了 JPA 的實現,並被行業和使用者採用。這些包括 Hibernate(由 JBoss 和 Red Hat 收購),TopLink(由 Oracle 收購)和 Kodo JDO(由 BEA 和 Oracle 收購)。其他支援 JPA 的產品包括 Cocobase(由 Thought Inc. 收購)和 JPOX。
Spring Boot JPA - 基本使用
匯入jar
在pom.xml中加入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
建立實體
@Entity
public class User{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String phone;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
Dao層介面
public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
User findByPhone(String phone);
User findByPhoneAndFlag(String phone, Integer flag);
User findByIdAndFlag(Integer userId, Integer flag);
User findByOpenIdAndFlag(String openId, Integer flag);
Page<User> findByFlag(Integer flag, Pageable pageable);
List<User> findByNewPersonAndFlagOrderByCreateTimeAsc(Integer isNewPerson, Integer flag);
User findById(Integer toBeFollowID);
List<User> findByFlagAndNewPerson(Integer flag, Integer isNewPerson, Pageable pageable);
List<User> findByNicenameIsLikeAndFlagAndNewPerson(String searchName, Integer flag, Integer isNewPerson, Pageable pageable);
}
spring data jpa 預設預先生成了一些基本的CURD的方法,例如:增、刪、改等等
userDao.save(user); //儲存一個物件
userDao.save(new List<User>); //儲存多個物件
userDao.delete(user); //刪除一個物件
userDao.delete(id); //通過id刪除
userDao.deleteAll(); //刪除所有
userDao.delete(new ArrayList<>()); //批量刪除
userDao.findOne(id); //通過id獲取
userDao.getOne(id); //通過id獲取 不推薦使用
userDao.findAll(pageable); //分頁查詢所有
userDao.exists(id); //id是否存在
......
除此之外還提供了自定義方法名的方式查詢(在userDao中)
User findByOpenIdAndFlag(String openId, Integer flag);
//等同於
SELECT * FROM 'user' WHERE open_id =?1 AND flag = ?2
具體的關鍵字,使用方法和生產成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 | 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 |
EndingWith | findByFirstnameEndingWith | where x.firstname like ?1 |
Containing | findByFirstnameContaining | where x.firstname like ?1 |
OrderBy | findByAgeOrderByLastnameDesc | where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | where x.lastname <> ?1 |
In | findByAgeIn(Collection<Age> ages) | where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<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) |
分頁查詢
直接在controller層封裝好Pageable物件即可
@GetMapping("findBanners")
public Page<Banner> findBanners(@PageableDefault(sort = {"priority"}, direction=Sort.Direction.ASC) Pageable pageable)
注意: #ad1f1f
前端直接在請求的最後拼接上?page=0&size=10
如果前端不傳page 和 size 這兩個引數過來,那麼@PageableDefault會預設為第1頁開始,每頁最大條數為10。需注意page為0時為第一頁。
在service中呼叫即可
//返回給客戶端的Page物件,其json格式為
{
"content": [],//資料內容
"first": true,//是否為第一頁
"last": true,//是否為最後一頁
"number": 0,//當前頁碼
"numberOfElements": 0,//當前頁中的實際資料條數
"size": 0,//一頁最大條數
"sort": { },//排序資訊
"totalElements": 0,//總條數
"totalPages": 0//總頁數
}
自定義分頁
public Page<Banner> findBanners(int id){
int page = 1;
int size = 10;
Sort sort = new Sort(Sort.Direction.DESC,"priority");
Pageable pageable = new PageRequest(page,size,sort);
return bannserDao.findById(id,pageable);
}
動態查詢
public Page<Admin> findAdminList(AdminCmsSearchVO adminCmsSearchVO, Pageable pageable) {
Specifications<Admin> spec = Specifications.where(commonSpecUtil.like("name", adminCmsSearchVO.getName()))
.and(commonSpecUtil.equal("clazzType", adminCmsSearchVO.getClazzType()))
.and(commonSpecUtil.equal("flag",ModelContants.AdminContant.FLAG_IS_TRUE));
return adminDao.findAll(spec, pageable);
}
//(此程式碼由建東提供)
package com.luwei.common.utils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
* Created by jdq on 2017/8/8.
*/
@Component
public class CommonSpecUtil<T> {
/**
* 精確匹配(equal)
*
* @param srcName 欄位名
* @param targetProperty 匹配內容
* @return
*/
public Specification<T> equal(String srcName, Object targetProperty) {
if (targetProperty == null) {
return null;
}
return (root, query, cb) -> cb.equal(root.get(srcName), targetProperty);
}
/**
* 精確匹配(notEqual)
*
* @param srcName 欄位名
* @param targetProperty 匹配內容
* @return
*/
public Specification<T> notEqual(String srcName, Object targetProperty) {
if (targetProperty == null) {
return null;
}
return (root, query, cb) -> cb.notEqual(root.get(srcName), targetProperty);
}
/**
* 模糊匹配(like)
*
* @param srcName 欄位名
* @param targetProperty 匹配內容
* @return
*/
public Specification<T> like(String srcName, String targetProperty) {
if (StringUtils.isEmpty(targetProperty)) {
return null;
}
return (root, query, cb) -> cb.like(root.get(srcName), "%" + targetProperty + "%");
}
/**
* 日期範圍匹配(timeBetween)
*
* @param srcName 欄位名
* @param startTimeStr 開始時間
* @param endTimeStr 結束時間
* @return
*/
public Specification<T> timeBetween(String srcName, String startTimeStr, String endTimeStr) {
Date startTime, endTime;
if (StringUtils.isEmpty(startTimeStr)) {
startTime = DateUtils.getDate2("1970-01-01 00:00:00");
} else {
startTime = DateUtils.getDate2(startTimeStr + " 00:00:00");
}
if (StringUtils.isEmpty(endTimeStr)) {
endTime = new Date();
} else {
endTime = DateUtils.getDate2(endTimeStr + " 23:59:59");
}
return (root, query, cb) -> cb.between(root.get(srcName), startTime, endTime);
}
public Specification<T> parkingOrderTime(String srcName,String startTimeStr,String endTimeStr) {
Date startTime,endTime;
startTime=DateUtils.getDate2(DateUtils.tostartDayTime(startTimeStr));
endTime = DateUtils.getDate2(DateUtils.toEndDayTime(endTimeStr));
return (root, query, cb) -> cb.between(root.get(srcName), startTime,endTime);
}
/**
* 日期範圍匹配(timeBetween)
*
* @param srcName 欄位名
* @param startTime 開始時間
* @param endTime 結束時間
* @return
*/
public Specification<T> timeBetween(String srcName, Date startTime, Date endTime) {
if (org.springframework.util.StringUtils.isEmpty(startTime)) {
return null;
}
if (org.springframework.util.StringUtils.isEmpty(endTime)) {
return null;
}
return (root, query, cb) -> cb.between(root.get(srcName), startTime, endTime);
}
/**
* 數值範圍匹配(between)
*
* @param srcName 欄位名
* @param start 開始
* @param end 結束
* @return
*/
public Specification<T> between(String srcName, Integer start, Integer end) {
if (org.springframework.util.StringUtils.isEmpty(start)) {
return null;
}
if (org.springframework.util.StringUtils.isEmpty(end)) {
return null;
}
return (root, query, cb) -> cb.between(root.get(srcName), start, end);
}
/**
* 大於等於(greaterThanOrEqualTo)
*
* @param srcName 欄位名
* @param value 數值
* @return
*/
public Specification<T> greaterThanOrEqualTo(String srcName, Integer value) {
if (org.springframework.util.StringUtils.isEmpty(value)) {
return null;
}
return (root, query, cb) -> cb.greaterThanOrEqualTo(root.get(srcName), value);
}
/**
* 小於等於(lessThanOrEqualTo)
*
* @param srcName 欄位名
* @param value 數值
* @return
*/
public Specification<T> lessThanOrEqualTo(String srcName, Integer value) {
if (org.springframework.util.StringUtils.isEmpty(value)) {
return null;
}
return (root, query, cb) -> cb.lessThanOrEqualTo(root.get(srcName), value);
}
/**
* in條件帥選(in)
*
* @param srcName 欄位名
* @param list 集合
* @return
*/
public Specification<T> in(String srcName, List<Integer> list) {
if (org.springframework.util.StringUtils.isEmpty(list)) {
return null;
}
return (root, query, cb) -> cb.and(root.get(srcName).in(list));
}
/**
* 不為空(isNotNull)
*
* @param srcName 欄位名
* @return
*/
public Specification<T> isNotNull(String srcName) {
return (root, query, cb) -> cb.isNotNull(root.get(srcName));
}
/**
* 倒序(desc)
*
* @param srcName 欄位名
* @return
*/
public Specification<T> desc(String srcName) {
return (root, query, cb) -> query.orderBy(cb.desc(root.get(srcName).as(Integer.class))).getRestriction();
}
/**
* 升序(asc)
*
* @param srcName 欄位名
* @return
*/
public Specification<T> asc(String srcName) {
return (root, query, cb) -> query.orderBy(cb.asc(root.get(srcName).as(Integer.class))).getRestriction();
}
}
動態查詢的條件:
1.adminDao要繼承JpaSpecificationExecutor
2.CommonSpecUtil提供了各種匹配的方法。如equals,like,notEqual…
參考部落格
部分引用於袁荻的部落格
原文地址
廣州蘆葦科技Java開發團隊
蘆葦科技-廣州專業網際網路軟體服務公司
抓住每一處細節 ,創造每一個美好
關注我們的公眾號,瞭解更多
想和我們一起奮鬥嗎?lagou搜尋“ 蘆葦科技 ”或者投放簡歷到 [email protected] 加入我們吧
關注我們,你的評論和點贊對我們最大的支援