Spring Data JPA

1.    概述spring

Spring JPA經過爲用戶統一建立和銷燬EntityManager,進行事務管理,簡化JPA的配置等使用戶的開發更加簡便。sql

Spring Data JPA是在Spring JPA的基礎上,對持久層作了簡化。用戶只需聲明持久層的接口,不須要實現該接口。Spring Data JPA內部會根據不一樣的策略、經過不一樣的方法建立Query操做數據庫。數據庫

 

2.    Spring Data JPA jar文件

到目前爲止,社區提供的最新的Spring Data JPA的jar文件以下:框架

-       spring-data-commons-1.8.0.RELEASE.jar:提供Spring Data共享的基礎框架,適合各個子項目使用,支持跨數據庫持久化。less

-       spring-data-jpa-1.6.0.RELEASE.jar:簡化建立 JPA 數據訪問層dom

-   spring-boot-starter-data-jpa-1.2.5.RELEASE(Sprig boot中使用)spring-boot

 

3.    Spring Data JPA jar

 

如今主流的JPA實裝包括Eclipselink、Toplink、OpenJPA和Hibernate。post

SpringFramework的JPA機能(org.springframework.orm.jpa 中提供)對這四種實裝都能支持。ui

但Spring JPA Data只支持JPA2.0,不支持JPA1.0。因此在TopLink上使用時可能會出錯。spa

 

4.    使用方法

Spring Data JPA 簡化持久層開發大體須要以下三個步驟。

       1)聲明持久層接口,該接口繼承Repository <T,ID>或其子接口,

           T是領域實體,ID是領域實體的主鍵類型。

      例:

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

 

       2)在持久層的接口中聲明須要的業務方法,Spring Data JPA將會根據指定的策略(請

  參照4.3章節)爲該方法生成實現代碼。用戶不須要實現該接口

      例:

List<User> findByLastname(String lastname);

 

        3)在Spring的配置文件中添加配置,爲聲明的接口設定代理對象。

      例:

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:jpa="http://www.springframework.org/schema/data/jpa

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/data/jpa

http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

 

<jpa:repositories base-package="com.jpa.data.sample"

entity-manager-factory-ref="entityManagerFactory"

 transaction-manager-ref="transactionManager"/>

  注:

          ①Spring會在」 base-package」中定義的package和其子package中搜尋繼承了Repository的接口。

          ②entityManagerFactory和transactionManager的定義,請參照Spring JPA的使用方法。

   

       4)得到並使用repository的實例。

           ①在Spring Container中使用

public class SomeClient {

@Autowired

private UserRepository repository;

   

public void doSomething() {

    User u = new User();

User user = repository. save (u);

}

}

 

            ② 在Spring Container外使用

RepositoryFactorySupport factory = … // Instantiate factory here

UserRepository repository = factory.getRepository(UserRepository.class);

 

4.1 Repository 接口

Repository是SpringData的核心接口,它並不提供任何方法,用戶須要本身定義須要的方法。

 

4.1.1 繼承Repository接口的兩種方法

 ①直接繼承

public interface UserDao extends Repository<User, Long> { …… }

 

 ②使用@RepositoryDefinition註解

@RepositoryDefinition(domainClass = User.class, idClass = Long.class)

 public interface UserDao { …… }

 

4.1.2 其餘Repository接口

CrudRepository

(Spring Data提供)

繼承Repository,提供增刪改查方法,能夠直接調用。

PagingAndSortingRepository

(Spring Data提供)

繼承CrudRepository,增長了分頁查詢和排序兩個方法

JpaRepository

(Spring Data JPA提供)

繼承PagingAndSortingRepository,是針對JPA技術的接口,提供flush(),saveAndFlush(),deleteInBatch()等方法

 

4.1.3 用戶組定義實現(Spring Data提供的機能)

Spring Data的repository容許用戶自定義操做數據庫的方法。用戶能夠與原有的repository結合起來使用。

 

4.1.3.1 爲單個的repository添加用戶行爲

   實現步驟以下:

      ①定義一個接口,在此接口中聲明自定義的操做數據庫的方法

interface UserRepositoryCustom {

public void someCustomMethod(User user);

}

 

      ② ①中定義接口的實現

class UserRepositoryImpl implements UserRepositoryCustom {

public void someCustomMethod(User user) {

//操做數據庫

}

}

 

      ③定義一個接口同時繼承Spring原有Repository和①中定義接口

public interface UserRepository extends CrudRepository<User, Long>, UserRepositoryCustom {

……

}

 

      ④在Spring的配置文件中添加配置

<!--搜尋名爲userRepositoryImpl的 class做爲自定義repository的實現-->

<repositories base-package=" com.jpa.data.sample ">

<repository id="userRepository" />

</repositories>

<!--搜尋名爲userRepositoryFooBar的 class做爲自定義repository的實現-->

<repositories base-package=" com.jpa.data.sample " repository-impl-postfix="FooBar">

<repository id="userRepository" />

</repositories>

 

4.1.3.2爲全部的repository添加用戶行

   實現步驟以下:

      ①定義一個接口,聲明自定義的操做數據庫的方法

public interface MyRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {

void sharedCustomMethod(ID id);

}

 

      ②①中定義接口的實現,並繼承SimpleJpaRepository類

public class MyRepositoryImpl<T, ID extends Serializable>

extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {

public void sharedCustomMethod(ID id) {

// implementation goes here

}

}

 

      ③取代RepositoryFactoryBean成爲Spring Data repositores的base class,用於生成

          MyRepositoryImpl實例

public class MyRepositoryFactoryBean<T extends JpaRepository<?, ?>

extends JpaRepositoryFactoryBean<T> {

protected RepositoryFactorySupport getRepositoryFactory(…) {

return new MyRepositoryFactory(…);

}

private static class MyRepositoryFactory extends JpaRepositoryFactory{

public MyRepositoryImpl getTargetRepository(…) {

return new MyRepositoryImpl(…);

}

public Class<? extends RepositorySupport> getRepositoryClass() {

return MyRepositoryImpl.class;

}

}

}

 

      ④在Spring的配置文件中添加配置

<repositories base-package=" com.jpa.data.sample "

factory-class="com.acme.MyRepositoryFactoryBean" />

 

4.2 Query的三種方式

Spring Data JPA中除了提供經過解析方法名的方式來建立Query以外,還提供了@Query和JPA NamedQueries兩種方法。

 

解析方法名

Spring Data JPA會經過解析用戶在持久層接口中定義的方法名來生成相應的query語句。(詳細的解析方法名的規則請參照Spring Data JPA官方文檔)

例:

持久層接口中定義以下:

public interface UserRepository extends Repository<User, Long> {

List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);

}

將會解析爲以下的query

select u from User u where u.emailAddress = ?1 and u.lastname = ?2

 

解析時能被識別的keyword和包含這些keyword的方法會被解析成什麼樣的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

Between

findByStartDateBetween

… where x.startDate between 1? and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?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

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

 

使用@Query

能夠在自定義的查詢方法上使用@Query來指定該方法要執行的查詢語句,好比:  

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.emailAddress = ?1")

  User findByEmailAddress(String emailAddress);

}

注意:

1:方法的參數個數必須和@Query裏面須要的參數個數一致

2:若是是like,後面的參數須要前面或者後面加「%」

 

使用@Param能夠用命名參數來代替位置編號,將方法參數與 JPQL 中的命名參數對應。JPQL 語句中經過": 變量"的格式來指定參數

例:

public interface UserRepository extends JpaRepository<User, Long> {

 @Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")

 User findByLastnameOrFirstname(@Param("lastname") String lastname,

                                   @Param("firstname") String firstname);

}

 

若是要生成更新類的Query語句,在@Query以前添加@Modifying便可。

例:

@Modifying

@Query("update User u set u.firstname = ?1 where u.lastname = ?2")

int setFixedFirstnameFor(String firstname, String lastname);

注意:

1:方法的返回值應該是int,表示更新語句所影響的行數。

2:在調用的地方必須加事務,沒有事務不能正常執行。

 

使用JPA NamedQueries

在JPA配置文件中定義

在META-INF文件下的JPA的配置文件orm.xml中,經過<named-query/>元素進行定義。

例:

<named-query name="User.findByLastname">

  <query>select u from User u where u.lastname = ?1</query>

</named-query>

 

經過Annotation配置

在Entity Bean中使用@NamedQuery(或@NamedNativeQuery)進行配置。

例:

@Entity

@NamedQuery(name = "User.findByEmailAddress",

  query = "select u from User u where u.emailAddress = ?1")

public class User {

}

 

注意

①  上述兩種方法都須要知足」DomainClass.methodName()」的命名規則。

②  不管是在JPA配置文件中使用<named-query/>定義仍是在Entity Bean中使用@NamedQuery進行配置,

   在持久層的接口中必須聲明對應的方法。

例:

public interface UserRepository extends JpaRepository<User, Long> {

List<User> findByLastname(String lastname);

User findByEmailAddress(String emailAddress);

}

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   

4.3 Query的策略

建立Query的策略有以下3種:???

  • create:只經過解析方法名來建立Query。忽略@Query和NamedQuery方法。
  • use-declared-query:若是方法經過 @Query 指定了查詢語句,則使用該語句建立Query;若是沒有,則查找是否認義了符合條件的Named Query,若是找到,則使用該命名查詢;若是二者都沒有找到,則拋出異常。
  • create-if-not-found (default):若是方法經過 @Query 指定了查詢語句,則使用該語句建立查詢;若是沒有,則查找是否認義了符合條件的Named Query,若是找到,則使用該Named Query;若是二者都沒有找到,則經過解析方法名字來建立Query。

 

<jpa:repositories>中提供的query-lookup-strategy 屬性能夠用來定義查找Query的順序。定義方法以下:

<jpa:repositories base-package=" com.jpa.data.sample" query-lookup-strategy="create"/>

 

5.    Specifications(非重要機能)

JPA2.0提供了Criteria API(具體的適用方法請參照JPA2.0的官方文檔),能夠用於動態的生成query,而且在運行時檢證其正確性。Spring Data JPA支持Criteria查詢。使用方法以下

①     自定義Repository接口並繼承JpaSpecificationExecutor

public interface UserRepository extends CrudRepository<User, Long>, JpaSpecificationExecutor {

②     自定義Specification,實現Specification接口

public Specification<User> isYoungFemaleUser() {

return new Specification<User>() {

public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query,CriteriaBuilder cb) {

              Predicate isFemaleUser = cb.equal(root.get("sex").as(String.class), "girl");

              Predicate isYoungUser = cb.lessThan(root.get("age").as(Integer.class), 18);

             

// 2個檢索條件同時使用

query.where(cb.and(isFemaleUser,isYoungUser));  

              return query.getRestriction();  

}

};

 

③     調用自定義的Repository中的方法(可由JpaSpecificationExecutor提供),例如findAll

List<User> users = userRepository.findAll(isYoungFemaleUser ());

 

6.    事務處理

除了將查詢的方法設爲只讀事務(@Transactional(readOnly=true))外,其餘事務屬性均採用默認值(@Transactional)。

用戶能夠在接口方法上使用 @Transactional 顯式指定事務屬性,該值覆蓋 Spring Data JPA 提供的默認值。同時,也能夠在業務層方法上使用 @Transactional 指定事務屬性,這主要針對一個業務層方法屢次調用持久層方法的狀況。持久層的事務會根據設置的事務傳播行爲來決定是掛起業務層事務仍是加入業務層的事務。@Transactional的詳細用法請參照Spring的官方文檔。

 

7.    Auditing(非重要機能)

Spring Data JPA也提供了對auditing的支持。在實體建立或更新的時候能夠把操做時間或操做人一併更新到數據庫裏去。使用方法以下

①     Entity類拓展Auditable接口,或者繼承AbstractPersistable或AbstractAuditable類

@Entity

public class Conference extends AbstractAuditable<User, Long>{……}

Auditable接口、AbstractPersistable或AbstractAuditable類中提供了得到建立或更新Entity的操做時間或操做人的方法,好比

U getCreatedBy();

void setCreatedBy(U createdBy);

DateTime getCreatedDate();

void setCreated(Date creationDate);

U getLastModifiedBy();

void setLastModifiedBy(U lastModifiedBy);

DateTime getLastModifiedDate();

void setLastModified(Date lastModifiedDate);

 

②     在orm.xml中進行配置

<persistence-unit-metadata>

<persistence-unit-defaults>

<entity-listeners>

<entity-listener

class="org.springframework.data.jpa.domain.support.AuditingEntityListener " />

</entity-listeners>

</persistence-unit-defaults>

</persistence-unit-metadata>

 

③     聲明AuditorAware的拓展類,在此類中用戶能夠取到當前的用戶,在運行時將auditor注入到AuditingEntityListener

public class AuditorAwareImpl implements AuditorAware<Object> {

}

 

④     在配置文件中配置配置③中的拓展類

<jpa:auditing auditor-aware-ref=" AuditorAwareImpl " />

 

8.    QueryDSL

下次有空在另外一篇文章裏面細述。

 

 

 

============================

Spring Data JPA有什麼

主要來看看Spring Data JPA提供的接口,也是Spring Data JPA的核心概念:
1:Repository:最頂層的接口,是一個空的接口,目的是爲了統一全部Repository的類型,且能讓組件掃描的時候自動識別。
2:CrudRepository :是Repository的子接口,提供CRUD的功能
3:PagingAndSortingRepository:是CrudRepository的子接口,添加分頁和排序的功能
4:JpaRepository:是PagingAndSortingRepository的子接口,增長了一些實用的功能,好比:批量操做等。
5:JpaSpecificationExecutor:用來作負責查詢的接口
6:Specification:是Spring Data JPA提供的一個查詢規範,要作複雜的查詢,只需圍繞這個規範來設置查詢條件便可
 

表A 主鍵id  save 主鍵自動增加,保存成功。更新時候,setId(傳入主鍵),jpa 會自動更新全部字段,前提是使用save 方法,jpa 無直接的update 語句。此時寫update sql 會比較長,由於要寫全部的列。。。。

相關文章
相關標籤/搜索