SpringData :Spring的一個子項目。用於簡化數據庫訪問,支持NoSQL和關係數據存儲。其主要目標是使用數據庫的訪問變得方便快捷。java
SpringData 項目所支持NoSQL存儲:mysql
SpringData 項目所支持的關係數據存儲技術:web
Spring Data : 致力於減小數據訪問層 (DAO) 的開發量. 開發者惟一要作的,就只是聲明持久層的接口,其餘都交給 Spring Data JPA 來幫你完成!spring
框架怎麼可能代替開發者實現業務邏輯呢?好比:當有一個 UserDao.findUserById()
這樣一個方法聲明,大體應該能判斷出這是根據給定條件的 ID 查詢出知足條件的 User 對象。Spring Data JPA 作的即是規範方法的名字,根據符合規範的名字來肯定方法須要實現什麼樣的邏輯。sql
第一步 添加依賴數據庫
springBoot相關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驅動app
<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)dom
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 接口是 Spring Data 的一個核心接口,它不提供任何方法,開發者須要在本身定義的接口中聲明須要的方法
public interface Repository<T, ID extends Serializable> { }
Spring Data可讓咱們只定義接口,只要遵循 Spring Data的規範,就無需寫實現類。
與繼承 Repository 等價的一種方式,就是在持久層接口上使用 @RepositoryDefinition
註解,併爲其指定 domainClass
和idClass
屬性。以下兩種方式是徹底等價的
/** * 主鍵方式定義接口 */ @RepositoryDefinition(domainClass=Person.class,idClass=Integer.class) public interface PersonRepsotory{} /** * 繼承方式定義接口 * 經常使用 */ public interface PersonRepsotory extends JpaRepository<Person, Integer>{}
如圖,基礎的 Repository 提供了最基本的數據訪問功能,其幾個子接口則擴展了一些功能。它們的繼承關係以下: Repository
: 僅僅是一個標識,代表任何繼承它的均爲倉庫接口類 CrudRepository
: 繼承 Repository,實現了一組 CRUD 相關的方法 PagingAndSortingRepository
: 繼承 CrudRepository,實現了一組分頁排序相關的方法 JpaRepository
: 繼承 PagingAndSortingRepository,實現一組 JPA 規範相關的方法 自定義的 XxxxRepository
: 須要繼承 JpaRepository,這樣的 XxxxRepository接口就具有了通用的數據訪問控制層的能力。 JpaSpecificationExecutor
: 不屬於Repository體系,實現一組 JPA Criteria 查詢相關的方法
簡單條件查詢: 查詢某一個實體類或者集合 按照 Spring Data 的規範,查詢方法以 find | read | get
開頭, 涉及條件查詢時,條件的屬性用條件關鍵字鏈接,要注意的是:條件屬性以首字母大寫。 例如:定義一個 Entity 實體類
public class User{ private String lastName; private String firstName; }
使用And條件鏈接時,應這樣寫: findByLastNameAndFirstName(String lastName,String firstName);
條件的屬性名稱與個數要與參數的位置與個數一一對應
支持的關鍵字
假如建立以下的查詢:findByUserDeptUuid()
,框架在解析該方法時,首先剔除 findBy
,而後對剩下的屬性進行解析,假設查詢實體爲UserInfo。
第一步:先判斷 userDeptUuid (根據 POJO 規範,首字母變爲小寫)是否爲查詢實體的一個屬性,若是是,則表示根據該屬性進行查詢;若是沒有該屬性,繼續第二步;
第二步:從右往左截取第一個大寫字母開頭的字符串(此處爲Uuid),而後檢查剩下的字符串是否爲查詢實體的一個屬性,若是是,則表示根據該屬性進行查詢;若是沒有該屬性,則重複第二步,繼續從右往左截取;最後假設 user 爲查詢實體的一個屬性;
第三步:接着處理剩下部分(DepUuid),先判斷 user 所對應的類型是否有deptUuid屬性,若是有,則表示該方法最終是根據 「 UserInfo.user.deptUuid」 的取值進行查詢;不然繼續按照步驟 二的規則從右往左截取,最終表示根據 「UserInfo.user.dept.uuid」 的值進行查詢。可能會存在一種特殊狀況,好比 UserInfo包含一個 user 的屬性,也有一個 userDep 屬性,此時會存在混淆。能夠明確在屬性之間加上 "_" 以顯式表達意圖,好比 "findByUser_DepUuid()" 或者 "findByUserDept_Uuid()"
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(); }