1. 概述spring
Spring JPA經過爲用戶統一建立和銷燬EntityManager,進行事務管理,簡化JPA的配置等使用戶的開發更加簡便。sql
Spring Data JPA是在Spring JPA的基礎上,對持久層作了簡化。用戶只需聲明持久層的接口,不須要實現該接口。Spring Data JPA內部會根據不一樣的策略、經過不一樣的方法建立Query操做數據庫。數據庫
到目前爲止,社區提供的最新的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
如今主流的JPA實裝包括Eclipselink、Toplink、OpenJPA和Hibernate。post
SpringFramework的JPA機能(org.springframework.orm.jpa 中提供)對這四種實裝都能支持。ui
但Spring JPA Data只支持JPA2.0,不支持JPA1.0。因此在TopLink上使用時可能會出錯。spa
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); |
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" /> |
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
在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> |
在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); } |
建立Query的策略有以下3種:???
|
<jpa:repositories>中提供的query-lookup-strategy 屬性能夠用來定義查找Query的順序。定義方法以下:
<jpa:repositories base-package=" com.jpa.data.sample" query-lookup-strategy="create"/> |
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 ()); |
除了將查詢的方法設爲只讀事務(@Transactional(readOnly=true))外,其餘事務屬性均採用默認值(@Transactional)。
用戶能夠在接口方法上使用 @Transactional 顯式指定事務屬性,該值覆蓋 Spring Data JPA 提供的默認值。同時,也能夠在業務層方法上使用 @Transactional 指定事務屬性,這主要針對一個業務層方法屢次調用持久層方法的狀況。持久層的事務會根據設置的事務傳播行爲來決定是掛起業務層事務仍是加入業務層的事務。@Transactional的詳細用法請參照Spring的官方文檔。
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 " /> |
下次有空在另外一篇文章裏面細述。
============================
Spring Data JPA有什麼
表A 主鍵id save 主鍵自動增加,保存成功。更新時候,setId(傳入主鍵),jpa 會自動更新全部字段,前提是使用save 方法,jpa 無直接的update 語句。此時寫update sql 會比較長,由於要寫全部的列。。。。