1. 程式人生 > >springBoot+SpringData 整合入門

springBoot+SpringData 整合入門

comment private 創建 img and aso ans 簡單 標識

SpringData概述

SpringData :Spring的一個子項目。用於簡化數據庫訪問,支持NoSQL和關系數據存儲。其主要目標是使用數據庫的訪問變得方便快捷。

SpringData 項目所支持NoSQL存儲:

  • MongoDB(文檔數據庫)
  • Neo4j(圖形數據庫)
  • Redis(鍵/值存儲)
  • Hbase(列族數據庫)

SpringData 項目所支持的關系數據存儲技術:

  • JDBC
  • JPA

Spring Data : 致力於減少數據訪問層 (DAO) 的開發量. 開發者唯一要做的,就只是聲明持久層的接口,其他都交給 Spring Data JPA 來幫你完成!

框架怎麽可能代替開發者實現業務邏輯呢?比如:當有一個 UserDao.findUserById()

這樣一個方法聲明,大致應該能判斷出這是根據給定條件的 ID 查詢出滿足條件的 User 對象。Spring Data JPA 做的便是規範方法的名字,根據符合規範的名字來確定方法需要實現什麽樣的邏輯。

SpringBoot+SpringData 整合入門

第一步 添加依賴

springBoot相關

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

mysql驅動

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

springDataJPA相關

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

第二步 配置文件 (src/main/resources/application.yml)

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/springboot-springdata
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  jpa:
    #指定數據庫
    database: mysql
    #打印sql
    show-sql: true
    hibernate:
      #開啟數據庫更新表
      ddl-auto: update
      #指定命名策略
      naming:
        strategy: org.hibernate.cfg.ImprovedNamingStrategy
    properties:
      hibernate:
        #Hibernate方言
        dialect: org.hibernate.dialect.MySQL5Dialect

第三步 創建Repository接口、Entity

Repository接口

public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {}

Entity(啟動項目會自動創建表)

@DynamicInsert(true)
@DynamicUpdate(true)
@Table(name = "sys_user")
public class User implements Serializable{

    private static final long serialVersionUID = 6425411731900579688L;

    @Id
    @GeneratedValue
    @Column(columnDefinition = "bigint(20) comment '主鍵'", nullable = false)
    private long id;

    @Column(columnDefinition = "varchar(255) comment '用戶姓名'",nullable = false, unique = true)
    private String username;

    @Column(columnDefinition = "varchar(255) comment '密碼'", nullable = false)
    private String password;

    @Column(columnDefinition = "int(10) comment '年齡'", nullable = false)
    private int age;

}

這樣就整合完成,可以創建接口進行單元測試了

Repository接口概述

Repository 接口是 Spring Data 的一個核心接口,它不提供任何方法,開發者需要在自己定義的接口中聲明需要的方法

public interface Repository<T, ID extends Serializable> { } 

Spring Data可以讓我們只定義接口,只要遵循 Spring Data的規範,就無需寫實現類。

與繼承 Repository 等價的一種方式,就是在持久層接口上使用 @RepositoryDefinition 註解,並為其指定 domainClassidClass屬性。如下兩種方式是完全等價的

/**
 * 主鍵方式定義接口
 */
@RepositoryDefinition(domainClass=Person.class,idClass=Integer.class)
public interface PersonRepsotory{}

/**
 * 繼承方式定義接口
 * 常用
 */
public interface PersonRepsotory extends JpaRepository<Person, Integer>{}

Repository的子接口

技術分享圖片

如圖,基礎的 Repository 提供了最基本的數據訪問功能,其幾個子接口則擴展了一些功能。它們的繼承關系如下:
Repository: 僅僅是一個標識,表明任何繼承它的均為倉庫接口類
CrudRepository: 繼承 Repository,實現了一組 CRUD 相關的方法
PagingAndSortingRepository: 繼承 CrudRepository,實現了一組分頁排序相關的方法
JpaRepository: 繼承 PagingAndSortingRepository,實現一組 JPA 規範相關的方法
自定義的 XxxxRepository: 需要繼承 JpaRepository,這樣的 XxxxRepository接口就具備了通用的數據訪問控制層的能力。
JpaSpecificationExecutor: 不屬於Repository體系,實現一組 JPA Criteria 查詢相關的方法

SpringData 查詢方法命名規範

簡單條件查詢: 查詢某一個實體類或者集合
按照 Spring Data 的規範,查詢方法以 find | read | get開頭, 涉及條件查詢時,條件的屬性用條件關鍵字連接,要註意的是:條件屬性以首字母大寫。
例如:定義一個 Entity 實體類

class User{ 
    private String firstName; 
    private String lastName; 
} 

使用And條件連接時,應這樣寫:findByLastNameAndFirstName(String lastName,String firstName);條件的屬性名稱與個數要與參數的位置與個數一一對應

支持的關鍵字

技術分享圖片

技術分享圖片

springData 查詢方法解析原理

假如創建如下的查詢:findByUserDeptUuid(),框架在解析該方法時,首先剔除 findBy,然後對剩下的屬性進行解析,假設查詢實體為UserInfo。

第一步:先判斷 userDeptUuid (根據 POJO 規範,首字母變為小寫)是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,繼續第二步;

第二步:從右往左截取第一個大寫字母開頭的字符串(此處為Uuid),然後檢查剩下的字符串是否為查詢實體的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,則重復第二步,繼續從右往左截取;最後假設 user 為查詢實體的一個屬性;

第三步:接著處理剩下部分(DepUuid),先判斷 user 所對應的類型是否有deptUuid屬性,如果有,則表示該方法最終是根據 “ UserInfo.user.deptUuid” 的取值進行查詢;否則繼續按照步驟 二的規則從右往左截取,最終表示根據 “UserInfo.user.dept.uuid” 的值進行查詢。可能會存在一種特殊情況,比如 UserInfo包含一個 user 的屬性,也有一個 userDep 屬性,此時會存在混淆。可以明確在屬性之間加上 "_" 以顯式表達意圖,比如 "findByUser_DepUuid()" 或者 "findByUserDept_Uuid()"

springData 實戰

命名方法查詢

public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
    /**
     * 根據username來獲取對應的user
     */
    User getByUsername(String username);

    /**
     * WHERE username LIKE %?
     */
    List<User> findByUsernameStartingWith(String username);

    /**
     * WHERE username LIKE ?%
     */
    List<User> findByUsernameEndingWith(String username);

    /**
     * WHERE username id < ?
     */
    List<User> findByIdLessThan(Long id);
}

註解查詢

public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
    /**
     * 查詢id 值最大的那個User 使用@Query 主鍵可以自定義JPQL語句以實現更靈活的查詢
     */
    @Query("SELECT u FROM User u WHERE u.id = (SELECT MAX(p.id) FROM User p)")
    User getMaxIdUser();

    /**
     * @Query 註解傳遞參數的方式一:占位符方式
     */
    @Query("SELECT u FROM User u WHERE u.username = ?1 AND u.age = ?2")
    List<User> testQueryAnnotationUser1(String username , Integer age);

    /**
     * @Query 註解傳遞參數的方式二:命名參數方式
     */
    @Query("SELECT u FROM User u WHERE u.username = :username AND u.age = :age")
    List<User> testQueryAnnotationUser2(@Param("username") String username , @Param("age")Integer age);
}

可以通過自定義的 JPQL 完成 UPDATE 和 DELETE 操作,註意: JPQL 不支持使用 INSERT。

在 @Query 註解中編JPQL 語句, 但必須使用 @Modifying 進行修飾. 以通知 SpringData, 這是一個 UPDATE 或 DELETE 操作。

UPDATE 或 DELETE 操作需要使用事務,可以使用註解@Transactional聲明,默認情況下, SpringData 的每個方法上有事務, 但都是一個只讀事務. 他們不能完成修改操作!

public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
    /**
     * @Query 註解update、delete操作,不支持insert
     */
    @Modifying
    @Query("UPDATE User u SET u.age = :age")
    @Transactional
    void updateUserAge(@Param("age") Integer age);
    
}

還可以使用原生Sql查詢,只需配置nativeQuery = true

public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
    /**
     * 設置 nativeQuery=true 即可以使用原生的 SQL 查詢
     */
    @Query(value = "SELECT COUNT(id) FROM sys_user" , nativeQuery = true)
    long getTotalCount();
}

springBoot+SpringData 整合入門