Spring Data JPA實現數據庫訪問

1.創建子模塊

右鍵點擊工程名[mapcloudservice] --> New --> Module --> 選擇Maven -->設置子模塊的名稱[datamanager] --> Finish
創建成功後如下圖所示:
在這裏插入圖片描述

2.配置pom.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

查看該項目的依賴關係圖:
方法一:右鍵點擊pom.xml文件中的任意處 --> Diagrams --> Show Dependencies
方法二:打開Maven工具欄,選擇 Show Dependencies

3.配置數據源

3.1 配置application.yml

首先在目錄/src/main/resources下創建application.yml,配置內容示例如下:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_example?serverTimezone=UTC&useSSL=true&autoReconnect=true&failOverReadOnly=false
    username: chaoshui
    password: 123456
  jpa:
    database: mysql
    show-sql: true
    hibernate:
      ddl-auto: update
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    open-in-view: false
3.2 注意事項

  命名策略physical-strategy使用:org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl,Hibernate 會默認以實體名和屬性名分別作爲表名及字段名進行映射,但是如果添加了註解@Table和@Column,則以註解屬性值進行映射命名。

4.創建Entity類

entity用於關聯映射數據庫中的一張表,entity類需要完成以下幾項工作:
(1)註解
  @Entity:表明這是一個實體類,與指定的數據庫表進行映射
  @Id:該屬性映射爲數據庫的主鍵
  @GeneratedValue:默認使用主鍵生成方式爲自增,hibernate會自動生成一個名爲HIBERNATE_SEQUENCE的序列
  @Table:指定映射的表名,若沒有則根據類的名稱進行映射
  @Column:指定映射的字段名
  @OneToOne/@OneToMany/ManyToOne:一對一、一對多、多對一的關聯
  
(2)定義屬性,類型爲私有
(3)創建所有屬性所對應的setter和getter方法
(4)創建帶參數的構造器和無參數的構造函數
(5)重寫父類中的eauals()方法和hashcode()方法
(6)實現序列化並賦予其一個版本號。
示例代碼:

package com.emapgo.datamanager.entity;

import net.bytebuddy.implementation.HashCodeMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.core.HashCodeCustomizer;
import sun.security.util.AuthResources_pt_BR;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "UserManage")
public class UserManage implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "clientID")
    private String clientID;

    @Column(name = "username")
    private String username;
    @Column(name = "password")
    private String password;
    @Column(name = "credentials")
    private String credentials;
    @Column(name = "grantType")
    private String grantType;
    @Column(name = "accessToken")
    private String accessToken;
    @Column(name = "tokenType")
    private String tokenType;
    @Column(name = "expireIN")
    private String expireIN;
    @Column(name = "scope")
    private String scope;

    public UserManage(){}

    public UserManage(String _clientID,
                      String _username,
                      String _password,
                      String _credentials,
                      String _grantType,
                      String _accessToken,
                      String _tokenType,
                      String _expireIN,
                      String _scope){
        this.clientID = _clientID;
        this.username = _username;
        this.password = _password;
        this.credentials = _credentials;
        this.grantType = _grantType;
        this.accessToken = _accessToken;
        this.tokenType = _tokenType;
        this.expireIN = _expireIN;
        this.scope = _scope;
    }

    // getter and setter methods
    public String getClientID() {
        return clientID;
    }
    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
    public String getCredentials() {
        return credentials;
    }
    public String getGrantType() {
        return grantType;
    }
    public String getAccessToken() {
        return accessToken;
    }
    public String getTokenType() {
        return tokenType;
    }
    public String getExpireIN() {
        return expireIN;
    }
    public String getScope() {
        return scope;
    }
    public void setClientID(String clientID) {
        this.clientID = clientID;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public void setCredentials(String credentials) {
        this.credentials = credentials;
    }
    public void setGrantType(String grantType) {
        this.grantType = grantType;
    }
    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }
    public void setTokenType(String tokenType) {
        this.tokenType = tokenType;
    }
    public void setExpireIN(String expireIN) {
        this.expireIN = expireIN;
    }
    public void setScope(String scope) {
        this.scope = scope;
    }
    
    @Override
    public String toString(){
        return  "Table-UserManage: " + "(" + this.clientID + "," + this.username + "," +
                this.password + "," + this.credentials + "," +
                this.grantType + "," + this.accessToken + "," +
                this.expireIN + "," + this.scope + ")\n";
    }

    // @Override
    // public int hashCode(){}

    // @Override
    // public boolean equals(Object obj){
    //     if(this == obj){
    //         return true;
    //     }
    //     if(obj == null || (getClass() != obj.getClass())){
    //         return false;
    //     }

    //     UserManage other = (UserManage) obj;
    //     if(!this.clientID.equals(other.clientID)){
    //         return false;
    //     }
    //     return true;
    // }
}

5.創建Repository接口

5.1創建repository接口

目的是通過repository訪問MySQL數據庫。

(1) 需要添加entity的類型和ID的類型用於表示關聯哪個entity。
(2) 增刪改查等操作方法只需按照書寫規範進行聲明,不需要實現,spring data jpa會在運行程序時根據方法名稱自動創建相關的實現,如下圖所示是CrudRepository接口中的全部方法

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
	// 保存指定的entity
    <S extends T> S save(S var1);
	// 保存所有的entity
    <S extends T> Iterable<S> saveAll(Iterable<S> var1);
	// 根據指定屬性返回entity
    Optional<T> findById(ID var1);
	// 判斷具有指定屬性的entity是否存在
    boolean existsById(ID var1);
	// 返回全部entity
    Iterable<T> findAll();
	// 根據指定屬性返回全部entity
    Iterable<T> findAllById(Iterable<ID> var1);
	// 返回entity的數量
    long count();
	// 根據指定的屬性刪除entity
    void deleteById(ID var1);
	// 刪除指定的entity
    void delete(T var1);
	// 刪除全部entity
	void deleteAll();
   
	void deleteAll(Iterable<? extends T> var1);   
}

(3) 方法名支持的Query關鍵字:

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, Null findByAge(Is)Null … 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 ages) … 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)

(4) 可以繼承的接口有四個:

Repository
CrudRepository
PagingAndSortingRepository
QueryByExampleExecutor

接口間繼承關係如下:
在這裏插入圖片描述

5.2基於Query註解的CRUD

  在繼承JpaRepository接口的方法中,可以在自定義的查詢方法上使用@Query,來指定該方法要執行的自定義的查詢語句。其中的value值可以是任意的查詢語句,同樣只需要進行方法的定義,無需進行實現。

5.3示例代碼
package com.emapgo.datamanager.repository;

import com.emapgo.datamanager.entity.UserManage;
import org.springframework.data.repository.CrudRepository;
import java.util.List;

public interface UserManageRepository extends CrudRepository<UserManage, String>
{
    // find
    List<UserManage> findAllByClientID(String clientID);
    List<UserManage> findAllByUsername(String username);
    List<UserManage> findAllByPassword(String password);
    List<UserManage> findAllByCredentials(String credentials);
    List<UserManage> findAllByGrantType(String grantType);
    List<UserManage> findAllByAccessToken(String accessToken);
    List<UserManage> findAllByTokenType(String tokenType);
    List<UserManage> findAllByExpireIN(String expireIN);
    List<UserManage> findAllByScope(String scope);

    UserManage findByClientID(String clientID);
    UserManage findByUsername(String username);
    UserManage findByPassword(String password);
    UserManage findByCredentials(String credentials);
    UserManage findByGrantType(String grantType);
    UserManage findByAccessToken(String accessToken);
    UserManage findByTokenType(String tokenType);
    UserManage findByExpireIN(String expireIN);
    UserManage findByScope(String scope);

    UserManage findByClientIDAndAccessToken(String cleintID, String accessToken);
    // ...等等

    // save
    // 略

    // update
    @Modifying
    @Transactional
    @Query(value = "update UserManage um set um.username = ?1 where um.clientID = ?2", nativeQuery = true)
    public void UpdateUsernameByClientID(String username, String clientID);
    //  ...等等

    // delete
    @Modifying
    @Transactional
    int deleteByClientID(String clientID);
    //  ...等等
}
5.3選擇性暴露部分CRUD方法

示例如下

@NoRepositoryBean
interface BaseRepository<T, ID> extends Repository<T, ID> {
	Optional<T> findById(ID id);
	<S extends T> S save(S entity);
}
interface UserManageRepository extends BaseRepository<User, Long> {
	// 略
}

6.創建Controller

7.添加主程序,測試

@SpringBootApplication
public class datamanageapplication {
    @Autowired
    UserManageRepository umr;

    public static void main(String[] args) {
        SpringApplication.run(datamanageapplication.class, args);
    }
    @Bean
    public CommandLineRunner userManageDemo(){
        System.out.println("-----------------------> **hello world** <-------------------------");

        return (args) -> {
            // insert
            umr.save(new UserManage("client_00", "lingwen_00", "123456_00", "creden_00", "grant_00","access_00", "token_00", "expire_00", "scope_00"));
            umr.save(new UserManage("client_01", "lingwen_01", "123456_01", "creden_01", "grant_01","access_01", "token_01", "expire_01", "scope_01"));


            // update
            umr.UpdateUsernameByClientID("lingwen_01", "client_00");
            System.out.println("Updated OK!");

            // fetch all records
            System.out.println("usermanager found with findAll(): ");
            System.out.println("----------------------------------");
            for(UserManage um : umr.findAll()){
                System.out.println(um.toString());
            }
            System.out.println();

            // fetch all records by clientID
            List<UserManage> um1 = umr.findAllByClientID("client_00");
            System.out.println("user manage found with findById(1L):");
            System.out.println("-----------------------------");
            System.out.println(um1.toString());

            // fetch all records by grant_type
            UserManage um2 = umr.findByScope("scope_00");
            System.out.println("user manage found with findById(2L):");
            System.out.println("-----------------------------");
            if(um2 != null){
                System.out.println(um2.toString());
            }else {
                System.out.println("cannot find any record that have attribute 'scope_00' in table UserManage!");
            }
            System.out.println();

            // fetch all user manage by ******
            // 略

            // delete
            umr.deleteByClientID("client_08");
            System.out.println("deleted OK!");

        };

   }


}

8.可能遇到的問題

寫entity類的時候,相關注解會出現紅色波浪線,並且在最終運行程序的時候會失敗(但是底層Hibernate顯示可以連接上數據庫),如下圖所示
在這裏插入圖片描述
解決方法:

  1. 點擊View --> ToolWindows -> Persistence,在左下區域出現Persistence
    在這裏插入圖片描述
  2. 右鍵點擊Entity --> Generate Persistence Mapping --> By Database Schema,在彈出的對話框中選擇Choose Data Source
    在這裏插入圖片描述
  3. 配置好數據庫相關的選項,可以點擊Test Connection測試能否連接成功
    在這裏插入圖片描述
  4. 完了之後點擊OK, 回到上一個對話框,點擊Database Schema mapping下的刷新,選中UserManage表 --> OK (必須點刷新,不點刷新不會自動出現這些內容)
    在這裏插入圖片描述
  5. 右鍵單擊Entity --> Assign Datasource 配置數據源
    在這裏插入圖片描述
    配置完以後,紅色波浪線消失,程序能夠正常運行,增刪改查等操作執行也沒有問題
    在這裏插入圖片描述
  6. 原因分析:暫時不清楚

參考資料

1.Spring Data JPA - Reference Documentation
2.Accessing Data with Spring Data JPA and MySQL
3.Getting Started with Spring Data JPA
4.spring data jpa 實戰之增刪改查(乾貨!你想要的查詢!)
5.Spring Data JPARepository Example
其他相關參考資料:
Create your first Java application
Spring MVC框架入門教程
MySQL Java tutorial

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章