Java後端愛上SpringBoot 第二節:Spring-Data-Jpa應用
Java後端愛上SpringBoot 第二節:Spring-Data-Jpa應用
- 何為Spring-Data-Jpa?
- 為什麼要用Spring-Data-Jpa?
- 使用JPA的一些思想上的轉變
- 一些連結
- SpringBoot整合Spring-Data-Jpa
- Spring-Data-Jpa應用
- 單表操作
- 多表操作
- 自定義動態條件拼接
- 自定義動態SQL查詢
何為Spring-Data-Jpa?
首先要明確的是JPA是一個規範,並不是一個框架,Spring-data-jpa就是一群Spring的摳腳大漢寫的一個符合JPA規範的一個封裝了不易上手的Hibernate的易上手
為什麼要用Spring-Data-Jpa?
- 能大大的簡化我們DAO層的開發(這個現如今的DAO層框架都能做到,但是Spring-Data-Jpa做的更多)
- 可以解放寫SQL的工作量
- 不用做資料庫初始化建表語句的管理
- Jdk生成要實行ORM(現在還沒有做到),在DAO層從一大堆SQL轉變成關係-物件的模式
- 有成熟的生態圈
還有別的一些好處,就在此不在說了,有興趣的道友可以自己搜一下。
使用JPA的一些思想上的轉變
-
要把傳統的在SQL上實現一大堆的業務邏輯分解成多的簡單的業務邏輯
貧道的栗子:在日常開發中,特別是三五年前的專案,有些程式設計師就是要用一個很大很大的SQL(超過100行的SQL)來做一個複雜的業務邏輯,他寫的程式碼讓後人無法可寫。 -
允許新增冗餘的欄位,以減少關聯查詢帶來的效率問題
-
在插入資料時儘量多做,在查詢資料時儘量少做
一些連結
- 【原創】純乾貨,Spring-data-jpa詳解,全方位介紹。
- spring data jpa 查詢自定義欄位,轉換為自定義實體
- Spring Data JPA 介紹和使用
- Spring-Data-Jpa官網文件
SpringBoot整合Spring-Data-Jpa
上一節其實都說了,在這裡再囉嗦一遍吧。
- Maven新增依賴包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
- 新增資料庫配置和JPA配置
spring:
###資料庫配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/spring?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
username: hyn
password: hyn1234
###JPA配置
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
generate-ddl: true
database: mysql
Spring-Data-Jpa應用
自動建表功能
建立一個實體SysUser
package com.hyn.spring.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
*
* @Title: SysUser.java
* @Package com.hyn.spring.domain
* @Description: TODO
* @author hyn
* @date 2018年12月9日 下午1:38:53
* @version V1.0
*/
@Entity
@Table(name = "sys_user")
@EntityListeners(AuditingEntityListener.class)
public class SysUser implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GenericGenerator(name = "idGenerator", strategy = "uuid") // 這個是hibernate的註解/生成32位UUID
@GeneratedValue(generator = "idGenerator")
/**
* 使用者ID
*/
@Column(columnDefinition="varchar(36) not null comment '使用者ID' ")
String id;
/**
*
* 使用者狀態
*/
@Column(columnDefinition = "enum('true','false') default 'true' not null comment '使用者狀態' ")
String status;
/**
* 郵箱
*/
@Column(columnDefinition = "varchar(20) not null default '' comment '使用者郵箱'" )
private String email;
/**
* 登入使用者名稱
*/
@Column(columnDefinition = "varchar(20) not null unique default '' comment '登入使用者名稱'" )
private String loginName;
/**
* 使用者名稱名稱
*/
@Column(columnDefinition = "varchar(10) not null default '' comment '使用者名稱稱'" )
private String userName;
/**
* 密碼策略
*/
@Column(columnDefinition = "varchar(100) not null default '888888' comment '登入密碼'" )
private String password;
/**
* 電話
*/
@Column(columnDefinition = "varchar(11) not null unique default '' comment '手機號碼'" )
private String phone;
/**
* 更新時間
*/
@Temporal(TemporalType.TIMESTAMP)
@Column(columnDefinition = "timestamp default current_timestamp on update current_timestamp comment '更新時間'")
@UpdateTimestamp
private Date moditime;
//省略get set
啟動專案會生成自動建表語句,如果你沒有看到自動建表,請檢查你的配置:
spring.jpa.properties.hibernate.hbm2ddl.auto有幾種狀態,我這裡去貼一下別人的:
- validate 載入hibernate時,驗證建立資料庫表結構
- create 每次載入hibernate,重新建立資料庫表結構,這就是導致資料庫表資料丟失的原因。
- create-drop 載入hibernate時建立,退出是刪除表結構
- update 載入hibernate自動更新資料庫結構
- none 不自動建表,也不檢查表結構
自動注入時間
細心的道友會發現為什麼實體上會加一個 @EntityListeners(AuditingEntityListener.class) 這個註解,在這裡解釋一下,這個註解是用來自動更新時間用的,比如每個表都應該有一個moditime欄位用來記錄這條資料最後更新的時間,如果讓自己手動去維護這個欄位就很麻煩,JPA提供了一個 @UpdateTimestamp註解來自動更新moditime,@EntityListeners 是用來開啟這個實體上自動更新時間的。不過除了需要加上這個註解以為,還去要在啟動類上加上 @EnableJpaAuditing註解,來開啟SpringBoot的Jpa的自動註解功能。
@SpringBootApplication
@EnableJpaAuditing
@EnableSwagger2
public class SpringFirstApplication {
public static void main(String[] args) {
SpringApplication.run(SpringFirstApplication.class, args);
}
}
單表操作
新增資料
建立DAO層
package com.hyn.spring.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import com.hyn.spring.entity.SysUser;
public interface ISysUserRepository extends JpaRepository<SysUser, String>,JpaSpecificationExecutor<SysUser>{
}
單個新增
@Override
public String save(SysUserVO sysUserVO) {
SysUser sysUser = new SysUser();
sysUser.setEmail(sysUserVO.getEmail());
sysUser.setLoginName(sysUserVO.getLoginName());
sysUser.setPassword(sysUserVO.getPassword());
sysUser.setPhone(sysUserVO.getPhone());
sysUser.setStatus(sysUserVO.getStatus());
sysUser.setUserName(sysUserVO.getUserName());
iSysUserRepository.save(sysUser);
return "success";
}
批量新增
@Override
@Transactional(rollbackOn=Exception.class)
public String batchSave(List<SysUserVO> sysUserVOs) {
List<SysUser> sysUsers = new ArrayList<>(sysUserVOs.size());
for (SysUserVO sysUserVO : sysUserVOs) {
SysUser sysUser = new SysUser();
sysUser.setEmail(sysUserVO.getEmail());
sysUser.setLoginName(sysUserVO.getLoginName());
sysUser.setPassword(sysUserVO.getPassword());
sysUser.setPhone(sysUserVO.getPhone());
sysUser.setStatus(sysUserVO.getStatus());
sysUser.setUserName(sysUserVO.getUserName());
sysUsers.add(sysUser);
}
iSysUserRepository.saveAll(sysUsers);
return "success";
}
注意進行事務控制,spring-data-jpa預設是開啟事務控制的,並且進行手動回滾 @Transactional(rollbackOn=Exception.class)
,這個是個好習慣。
注意這裡有坑:Spring-data-jpa自帶的批量插入介面,不適合大資料的插入,不是批量提交,是一條一條的INSERT來執行的,因為JPA每次都要檢查此條資料在資料庫中是否存在,如果存在是進行更新的。效率特別差,提交千條資料以上請使用別的方法。
批量儲存 Jpa saveAll() 和 JdbcTemplate batchUpdate()效率對比
刪除資料
刪除資料只是一行程式碼,但是不管在那個地方寫刪除資料是特別謹慎的事情,應該多進行驗證和確認。
@Override
public String delete(String id) {
iSysUserRepository.deleteById(id);
return "success";
}
注意點:刪除資料的時候如果有關聯關係,注意刪除關聯關係,才能刪除此條資料。
修改資料
修改資料需要驗證資料是否存在,在進行修改,修改資料的時候需要提交實體的所有屬性,否則會將實體的屬性更新為空!
@Override
public String update(SysUserVO sysUserVO) {
Optional<SysUser> optional = iSysUserRepository.findById(sysUserVO.getId());
if (optional.isPresent()) {
SysUser sysUser = optional.get();
sysUser.setEmail(sysUserVO.getEmail());
sysUser.setLoginName(sysUserVO.getLoginName());
sysUser.setPassword(sysUserVO.getPassword());
sysUser.setPhone(sysUserVO.getPhone());
sysUser.setStatus(sysUserVO.getStatus());
sysUser.setUserName(sysUserVO.getUserName());
sysUser.setId(sysUserVO.getId());
iSysUserRepository.save(sysUser);
return "success";
} else {
return "所更新的資料不存在!";
}
}
查詢資料
普通查詢
在ISysUserRepository加入以下方法:
/**
* 根據使用者登入名和密碼查詢
* @param loString
* @param password
*/
Optional<SysUser> findByLoginNameAndPassword(String loginname,String password);
注意:使用Java 8自帶的Optional來指示預設值,以避免空指標。
Distinct查詢
/**
* 根據使用者名稱 Distinct 查詢使用者
* @param userName
* @return
*/
Optional<List<SysUser>> findEmailDistinctByUserName(String userName);
IgnoreCase查詢
/**
* 根據使用者名稱 IgnoreCase 查詢使用者 忽略username大小寫
* @param userName
* @return
*/
Optional<List<SysUser>> findByUserNameIgnoreCase(String userName);
生成SQL:
SELECT
sysuser0_.id AS id1_0_,
sysuser0_.email AS email2_0_,
sysuser0_.login_name AS login_na3_0_,
sysuser0_.moditime AS moditime4_0_,
sysuser0_.PASSWORD AS password5_0_,
sysuser0_.phone AS phone6_0_,
sysuser0_.STATUS AS status7_0_,
sysuser0_.user_name AS user_nam8_0_
FROM
sys_user sysuser0_
WHERE
upper( sysuser0_.user_name ) = upper( ? )
ORDER BY查詢
/**
* 根據使用者名稱 OrderBy moditime 查詢使用者
* @param userName
* @return
*/
Optional<List<SysUser>> findByUserNameOrderByModitimeAsc(String userName);
生成SQL:
SELECT
sysuser0_.id AS id1_0_,
sysuser0_.email AS email2_0_,
sysuser0_.login_name AS login_na3_0_,
sysuser0_.moditime AS moditime4_0_,
sysuser0_.PASSWORD AS password5_0_,
sysuser0_.phone AS phone6_0_,
sysuser0_.STATUS AS status7_0_,
sysuser0_.user_name AS user_nam8_0_
FROM
sys_user sysuser0_
WHERE
sysuser0_.user_name =?
ORDER BY
sysuser0_.moditime ASC
OR查詢
/**
* 根據使用者名稱 or登入使用者 查詢使用者
* @param userName
* @param userName
* @return
*/
Optional<List<SysUser>> findByUserNameOrLoginName(String userName,String loginName);
生成SQL:
SELECT
sysuser0_.id AS id1_0_,
sysuser0_.email AS email2_0_,
sysuser0_.login_name AS login_na3_0_,
sysuser0_.moditime AS moditime4_0_,
sysuser0_.PASSWORD AS password5_0_,
sysuser0_.phone AS phone6_0_,
sysuser0_.STATUS AS status7_0_,
sysuser0_.user_name AS user_nam8_0_
FROM
sys_user sysuser0_
WHERE
sysuser0_.user_name =?
OR sysuser0_.login_name =?
還有Between,LessThan,GreaterThan,和Like表示式就個個舉例了,頻道有時間會補充的。
特殊引數查詢
/**
* 分頁查詢
* @param userName
* @param pageable
* @return
*/
Page<SysUser> findByUserName(String userName,Pageable pageable);
生成SQL:
SELECT
sysuser0_.id AS id1_0_,
sysuser0_.email AS email2_0_,
sysuser0_.login_name AS login_na3_0_,
sysuser0_.moditime AS moditime4_0_,
sysuser0_.PASSWORD AS password5_0_,
sysuser0_.phone AS phone6_0_,
sysuser0_.STATUS AS status7_0_,
sysuser0_.user_name AS user_nam8_0_
FROM
sys_user sysuser0_
WHERE
sysuser0_.user_name =?
ORDER BY
sysuser0_.moditime DESC
LIMIT ?
運用@Query
/**
* @Query 測試
* @param userName
* @return
*/
@Query(value = "select * from sys_user where user_name = ?1", nativeQuery = true)
Optional<List<SysUser>> findByUserName(String userName);
生成SQL:
select * from sys_user where email_address = ?1
寫成 select * 標識一下。
@Query 命名引數
/**
* @Query 測試
* @param userName
* @return
*/
@Query(value = "select * from sys_user where email like :email", nativeQuery = true)
Optional<List<SysUser>> findByEmail(@Param("email") String email);
生成SQL:
select * from sys_user where email like ?
貼一下官方的程式碼:
關鍵詞 | 樣品 | JPQL程式碼段 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
多表操作
在日常開發中,一定會有多表的關聯關係,不外乎一對一,一對多(多對一),多對對,這幾種關聯關係,以下依次介紹這幾種關聯關係的使用方式,來建立一個使用者-工位,使用者-部門,使用者-角色:
一對一關係
以上只建立了使用者的實體,而一個使用者只能擁有一個工位,因此使用者和工位是一對一關係
建立一個工位實體:
package com.hyn.spring.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
@Entity
@Table(name = "sys_station")
@EntityListeners(AuditingEntityListener.class)
public class SysStation implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GenericGenerator(name = "idGenerator", strategy = "uuid") // 這個是hibernate的註解/生成32位UUID
@GeneratedValue(generator = "idGenerator")
/**
* 工位ID
*/
@Column(columnDefinition="varchar(36) not null comment '工位ID' ")
String id;
/**
* 個人電腦編號
*/
@Column(columnDefinition = "varchar(10) not null unique default '' comment '個人電腦編號'" )
private String pcCode;
/**
* pcIP 個人電腦IP
*/
@Column(columnDefinition = "varchar(10) not null unique default '' comment '個人電腦IP'" )
private String pcIP;
//省略get set
}
為使用者實體和工位實體新增關聯關係,這個關聯關係是單向的也可以是雙向的,我們這裡建立一個雙向的。
在使用者實體中加入:
@OneToOne(mappedBy="sysUser")
SysStation sysStation;
在工位實體中加入:
@OneToOne
@JoinColumn(name="user_id")
SysUser sysUser;
@OneToOne表示實體與實體的關聯關係
@JoinColumn 定義了與關聯實體關聯的column欄位名
關於關聯雙向和單向的問題,道友可以參考這篇文章,寫的很詳細:hibernate的OneToOne對映
在新增工位方法中,新增關聯使用者的程式碼
@Override
public String save(SysStationVO sysStationVO) {
SysStation sysStation=new SysStation();
sysStation.setPcCode(sysStationVO.getPcCode());
sysStation.setPcIP(sysStationVO.getPcIP());
//關聯使用者
SysUser sysUser=new SysUser();
sysUser.setId(sysStationVO.getUserId());
sysStation.setSysUser(sysUser);
iSysStationRepository.save(sysStation);
return "success";
}
新增工位時就可以關聯使用者了
一對多(多對一)關係
多個使用者可以對應一個部門,一個部門有多個使用者,因此使用者-部門是一對多關係。
建立部門實體:
package com.hyn.spring.entity;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal
相關推薦
Java後端愛上SpringBoot 第二節:Spring-Data-Jpa應用
Java後端愛上SpringBoot 第二節:Spring-Data-Jpa應用
何為Spring-Data-Jpa?
為什麼要用Spring-Data-Jpa?
使用JPA的一些思想上的轉變
一些連結
SpringBoot整合Spring-Da
Java後端愛上SpringBoot 第一節:一個簡單的增刪改查
Java後端愛上SpringBoot 第一節:一個簡單的增刪改查
SpringBoot的魅力
一些連結
本文標籤
開發工具
Begin Hello World
寫一個使用者的增刪改查
實體
資料訪問層
檢視層
Java後端愛上SpringCloud 第二節:內部負載均衡 Ribbon和Feign
Java後端愛上SpringCloud 第一節:內部負載均衡 Ribbon和Feign
一些連結
Ribbon和Feign的區別和比較
當前架構
建立My-Spring-Ribbon
建立My-Spring-Feign
Ribbon呼叫
Java後端愛上SpringBoot 第五節:SpringBoot 批量提交
Java後端愛上SpringBoot 第五節:Spring-Data-JPA批量提交
Spring-Data-JPA批量提交
EntityManager批量提交
NamedParameterJdbcTemplate批量提交
PS:因為專案中用到
Java後端愛上SpringBoot 第四節:SpringBoot多資料來源
Java後端愛上SpringBoot 第四節:SpringBoot多資料來源
配置一個Oracle資料庫
配置一個SQLServer資料庫
配置一個MySql資料庫
PS:配置多資料來源這個事情是專案中用到的,之前也做過dome,但是做的時候又
Java後端愛上SpringBoot 第三節:整合Security & OAuth2(密碼模式 & 授權碼模式)
Java後端愛上SpringBoot 第三節:整合Security & OAuth2(密碼模式 & 授權碼模式)
一些連結
密碼模式
PS:網上SpringBoot整合Spring Security 和 OAuth2的文章很多,在這裡
Java後端愛上SpringCloud 第一節:服務註冊和發現 Eureka
Java後端愛上SpringCloud 第一節:服務註冊和發現 Eureka
一些連結
構建服務註冊中心EurekaServer
構建服務提供者EurekaClient
整合SpringBoot做視覺化監控
PS:還是老規矩,一些概念的東
Java後端愛上SpringCloud 第三節:熔斷器 Hystrix
Java後端愛上SpringCloud 第三節:熔斷器 Hystrix
一些連結
為什麼要用熔斷器?
Ribbon結合Hystrix
Feign結合Hystrix
PS:本來我都把這篇都寫過了,不過沒有儲存,現在重寫一遍。還有就是Hyst
url去重問題(百度Java後端面試一面第二題)
問題:有10 億個 url,每個 url 大小小於 56B,要求去重,記憶體只給你4G思路:1.首先將給定的url呼叫hash方法計算出對應的hash的value,在10億的url中相同url必然有著相
SpringBoot中使用Spring Data Jpa 實現簡單的動態查詢的兩種方法
ppr eat value table 得到 blog .net ride integer 首先謝謝大佬的簡書文章:http://www.jianshu.com/p/45ad65690e33#
這篇文章中講的是spring中使用spring data jpa,使用了xml配
SpringBoot操作之Spring-Data-Jpa(一)
runt 更新 drive oca 完成 work lin 進入 his Spring-Data-Jpa
JPA(Java Persistence API)定義了一系列對象持久化的標準,
目前實現這一規範的產品有Hibernate、TopLink等。
Spring Data
SpringBoot集成Spring-data-jpa訪問數據庫(四)
data inter 自動 繼承 users boot mea cte emp 相比使用JdbcTemplate,Spring-data-jpa使用起來更方便
1.首先UserService 繼承JpaRepository
public interface UserSer
springboot系列八 Spring-Data-JPA
JPA(Java Persistence API)是一種物件關係對映的ORM框架,springboot-jpa可以用簡單的配置來完成一些常規的資料庫crud操作
文件:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
DE
SpringBoot之結合Spring Data Jpa使用
1、建立SpringBoot工程,新增相關依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="htt
SpringBoot之使用Spring-data-jpa更加簡單優雅的訪問資料庫
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTests {@Autowiredprivate UserRepository
springboot集成Spring Data JPA數據查詢
服務器 find 管理 system 關系 git 它的 pos 解析 1、JPA介紹
JPA(Java Persistence API)是Sun官方提出的Java持久化規範。它為Java開發人員提供了一種對象/關聯映射工具來管理Java應用中的關系數據。它的出現主要是為
第65節:Java後端的學習之Spring基礎
Java後端的學習之Spring基礎
如果要學習spring,那麼什麼是框架,spring又是什麼呢?學習spring中的ioc和bean,以及aop,IOC,Bean,AOP,(配置,註解,api)-springFramework.
各種學習的知識點:
spring expressi
java後端websocket Spring整合
一、搭建環境
<dependency>
<groupId>org.springframework</groupId>
<artifactId&
Java後端的學習之Spring基礎
如果要學習spring,那麼什麼是框架,spring又是什麼呢?學習spring中的ioc和bean,以及aop,IOC,Bean,AOP,(配置,註解,api)-springFramework.
各種學習的知識點:
spring expression languagesp
java後端Spring POST請求
在Java後端中POST請求有很多種方法,這裡介紹三種方式:
普通方法
@RestController
@RequestMapping(value = "/user")
public