日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
開始使用SpringDataJPA

在我們剛剛發(fā)布項(xiàng)目Spring Data JPA的第一個(gè)里程碑時(shí),我想給你一個(gè)關(guān)于它的簡(jiǎn)要介紹.正如你所知道的,Spring framework 對(duì)于基于JPA的數(shù)據(jù)存取層提供了支持。那么 Spring Data JPA 是如何添加到Spring中的呢?回答這個(gè)問(wèn)題,我想從一個(gè)數(shù)據(jù)存取組件開始。這個(gè)組件提供了一個(gè)簡(jiǎn)單的域(domain),它是用純JPA和 Spring實(shí)現(xiàn)的,而且可以擴(kuò)展和改進(jìn)。在我們實(shí)現(xiàn)之后,我將用Spring Data JPA 來(lái)重構(gòu)它。你在以在 GitHub上找到這個(gè)小項(xiàng)目的每一次重構(gòu)的詳細(xì)指導(dǎo)。

域(The domain)

為了保持簡(jiǎn)單,我從最簡(jiǎn)單常用的域開始:客戶(Customer)和帳號(hào)(Account)

 
 
 
  1. @Entity
  2. public class Customer {
  3.   @Id
  4.   @GeneratedValue(strategy = GenerationType.AUTO)
  5.   private Long id;
  6.   private String firstname;
  7.   private String lastname;
  8.   // … methods omitted
  9. }
 
 
 
  1. @Entity
  2. public class Account {
  3.   @Id
  4.   @GeneratedValue(strategy = GenerationType.AUTO)
  5.   private Long id;
  6.   @ManyToOne
  7.   private Customer customer;
  8.   @Temporal(TemporalType.DATE)
  9.   private Date expiryDate;
  10.   // … methods omitted
  11. }

帳戶只有一個(gè)到期日(expriyDate).再無(wú)其他. - 它使用JPA注解.現(xiàn)在我們來(lái)看看管理帳號(hào)的組件.

 
 
 
  1. @Repository
  2. @Transactional(readOnly = true)
  3. class AccountServiceImpl implements AccountService {
  4.   @PersistenceContext
  5.   private EntityManager em;
  6.   @Override
  7.   @Transactional
  8.   public Account save(Account account) {
  9.     if (account.getId() == null) {
  10.       em.persist(account);
  11.       return account;
  12.     } else {
  13.       return em.merge(account);
  14.     }
  15.   }
  16.   @Override
  17.   public List findByCustomer(Customer customer) {
  18.     TypedQuery query = em.createQuery("select a from Account a where a.customer = ?1", Account.class);
  19.     query.setParameter(1, customer);
  20.     return query.getResultList();
  21.   }
  22. }

為了在后面重構(gòu)引入存儲(chǔ)層(repository layer)時(shí)不引起名稱沖突,我特意命名為 class*Service.但是在概念上,這個(gè)類是一個(gè)存儲(chǔ)對(duì)象,而不是服務(wù).事實(shí)上我們有嗎?

這個(gè)被@Repository 注釋的類拋出的異??梢员籗pring的DataAccessException捕獲。另外我們還用到了@Transactional 來(lái)保證 save(...) 操作的事務(wù)性和該類其他方法(這里是findByCustomer(...))的事務(wù)只讀標(biāo)識(shí)。這樣會(huì)對(duì)數(shù)據(jù)庫(kù)性能和我們持久化提供器的性能有一定的優(yōu)化。

由于我們不想讓程序員去決定什么時(shí)候調(diào)用EntityManager的merge(...)或者persist(...)方法。我們用了實(shí)體類主鍵字段內(nèi)容來(lái)判斷到底調(diào)用哪一個(gè)。這是判斷邏輯是全局通用的所以不用對(duì)每一個(gè)域?qū)ο蠖既ヂ暶鲗?shí)現(xiàn)。查詢方法也是很直觀的,我們寫一個(gè)查詢,綁定一個(gè)參數(shù)然后執(zhí)行這條查詢并取得結(jié)果。這個(gè)方法名其實(shí)已經(jīng)很直觀了,其實(shí)我們可以根據(jù)方法名就推出查詢語(yǔ)句,所以這里是可以提升一下的。(在后面可以直接按照這樣的模式寫方法名和參數(shù)而不需要去寫實(shí)現(xiàn),SPRING DATA JPA會(huì)根據(jù)你方法的命名自動(dòng)轉(zhuǎn)成SQL。(如果配合良好的數(shù)據(jù)庫(kù)設(shè)計(jì)和視圖設(shè)計(jì),省了不少事情))

Spring Data 存儲(chǔ)庫(kù)支持

在我們開始重構(gòu)該實(shí)現(xiàn)之前,看一下示例項(xiàng)目中包含的那些在重構(gòu)課程中能夠運(yùn)行的測(cè)試用例,確保那些代碼現(xiàn)在依舊能用。下面我們就來(lái)看如何改善我們的實(shí)現(xiàn)類。

Spring Data JPA 提供了一個(gè)存儲(chǔ)庫(kù)編程模型,首先,每一個(gè)受管理的領(lǐng)域?qū)ο蠖家幸粋€(gè)接口:

 
 
 
  1. public interface AccountRepository extends JpaRepository { … }

定義這個(gè)接口是出于兩個(gè)目的:首先,通過(guò)繼承JpaRepository我們獲得了一組泛型的CRUD方法,使我們能保存Accounts,刪除它們等等。其次,這使得Spring Data JPA存儲(chǔ)庫(kù)框架在classpath中掃描該接口,并為它創(chuàng)建一個(gè)Spring bean。

為了讓Spring創(chuàng)建一個(gè)實(shí)現(xiàn)該接口的bean,你僅需要使用Sping JPA"命名空間"并用適當(dāng)元素激活其對(duì)repository 的支持。

 
 
 
  1.  

這將掃描包含在包(package)com.acme.repositories下所有的繼承于JpaRepository的接口,并為該接口創(chuàng)建實(shí)現(xiàn)了SimpleJpaRepository的Sping bean。下面讓我們邁出第一步,稍微重構(gòu)我們的AccountService實(shí)現(xiàn)以便使用我們新介紹的repository接口。

 
 
 
  1. @Repository
  2. @Transactional(readOnly = true)
  3. class AccountServiceImpl implements AccountService {
  4.   @PersistenceContext
  5.   private EntityManager em;
  6.   @Autowired
  7.   private AccountRepository repository;
  8.   @Override
  9.   @Transactional
  10.   public Account save(Account account) {
  11.     return repository.save(account);
  12.   }
  13.   @Override
  14.   public List findByCustomer(Customer customer) {
  15.     TypedQuery query = em.createQuery("select a from Account a where a.customer = ?1", Account.class);
  16.     query.setParameter(1, customer);
  17.     return query.getResultList();
  18.   }
  19. }

重構(gòu)之后,我們將save(...)實(shí)際委派給repository。在默認(rèn)情況下,如果一個(gè)實(shí)體的主鍵屬性為null,那么repository實(shí)現(xiàn)會(huì)將其作為新建實(shí)體,正如你在前面的例子中所看到的一樣(注意,如果有必要,你可以對(duì)其進(jìn)行更為詳細(xì)的控制) 。除此之外,Spring Data JPA repository實(shí)現(xiàn)類已經(jīng)被@Transactional標(biāo)注的CRUD等方法可以摒棄@Transactional聲明。

下一步,我們將重構(gòu)查詢方法。并且使查詢方法與保存方法遵循相同的委派策略。我們?cè)诖鎯?chǔ)庫(kù)接口里面引入查詢方法并且將我們?cè)蟹椒ㄎ薪o新引進(jìn)的方法:

 
 
 
  1. @Transactional(readOnly = true) 
  2. public interface AccountRepository extends JpaRepository {
  3.   List findByCustomer(Customer customer); 
  4. }
 
 
 
  1. @Repository
  2. @Transactional(readOnly = true)
  3. class AccountServiceImpl implements AccountService {
  4.   @Autowired
  5.   private AccountRepository repository;
  6.   @Override
  7.   @Transactional
  8.   public Account save(Account account) {
  9.     return repository.save(account);
  10.   }
  11.   @Override
  12.   public List findByCustomer(Customer customer) {
  13.     return repository.findByCustomer(Customer customer);
  14.   }
  15. }

我們快速補(bǔ)充點(diǎn)事務(wù)處理的知識(shí)。在這種非常簡(jiǎn)單的情況下我們可以從AccountServiceImpl實(shí)現(xiàn)類中移除@Transaction注解,因?yàn)樵诖鎯?chǔ)庫(kù)的CRUD方法已經(jīng)進(jìn)行了事務(wù)管理,查詢方法在存儲(chǔ)庫(kù)接口中也已經(jīng)用@Transactional(readOnly = true)進(jìn)行了標(biāo)注。當(dāng)前設(shè)置——在service層次標(biāo)記為事務(wù)性的方法是一個(gè)最佳實(shí)踐(盡管在這里并不需要),因?yàn)楫?dāng)你在service層次查看方法時(shí)它可以顯式清楚的表明操作是在同一個(gè)事務(wù)中處理的。除此之外,如果一個(gè)service層次的方法修改了,需要進(jìn)行多次的存儲(chǔ)庫(kù)方法調(diào)用,這種情況下所有的代碼任然將會(huì)在同一個(gè)事務(wù)中執(zhí)行,因?yàn)樵诖鎯?chǔ)庫(kù)內(nèi)部的事務(wù)將會(huì)簡(jiǎn)單的加入到外部service層次的事務(wù)中。存儲(chǔ)庫(kù)事務(wù)行為和調(diào)整方式在 參考文檔中有詳細(xì)說(shuō)明。

嘗試再次運(yùn)行測(cè)試案例,看看測(cè)試是否正常運(yùn)行。打住,我們還沒(méi)有實(shí)現(xiàn)forfindByCustomer()方法,是不?那它是如何工作的呢?

#p#

查詢方法

當(dāng)Spring Data JPA為創(chuàng)建AccountRepository接口創(chuàng)建Spring實(shí)例的時(shí)候,它會(huì)檢查接口里面定義的所有查詢方法并且 為它們每個(gè)都派生一個(gè)查詢。默認(rèn)情況下,Spring Data JPA 將自動(dòng)解析方法名并以此創(chuàng)建一個(gè)查詢,查詢用標(biāo)準(zhǔn)JPA的API實(shí)現(xiàn)。在本例中findByCustomer(...)方法在邏輯上等同于JPQL 查詢“select a from Account a where a.customer = ?1”。解析方法名稱的解析器支持大量的關(guān)鍵字比如And,Or,GreaterThan,LessThan,Like,IsNull,Notand等等,如果您喜歡,您還可以添加ORDER BY子句。有關(guān)詳情請(qǐng)參閱文檔。這種機(jī)制給我們提供了一個(gè)查詢方法編程模型就像你在Grails 或 Spring Roo中用到的一樣。

現(xiàn)在,假設(shè)你想要顯式的使用指定的查詢。要做到這點(diǎn)你可以按照如下命名規(guī)約(本例中為Account.findByCustomer)在實(shí)體上通過(guò)注解或在orm.xml中聲明一個(gè)JPA命名的查詢來(lái)實(shí)現(xiàn),另外一個(gè)選擇就是你可以在存儲(chǔ)庫(kù)方法中使用@Query注解:

 
 
 
  1. @Transactional(readOnly = true)
  2. public interface AccountRepository extends JpaRepository {
  3.   @Query("")
  4.   List findByCustomer(Customer customer); 
  5. }

現(xiàn)在我們對(duì)CustomerServiceImpl用我們已經(jīng)看到的特性做一個(gè)前后對(duì)比:

 
 
 
  1. @Repository
  2. @Transactional(readOnly = true)
  3. public class CustomerServiceImpl implements CustomerService {
  4.   @PersistenceContext
  5.   private EntityManager em;
  6.   @Override
  7.   public Customer findById(Long id) {
  8.     return em.find(Customer.class, id);
  9.   }
  10.   @Override
  11.   public List findAll() {
  12.     return em.createQuery("select c from Customer c", Customer.class).getResultList();
  13.   }
  14.   @Override
  15.   public List findAll(int page, int pageSize) {
  16.     TypedQuery query = em.createQuery("select c from Customer c", Customer.class);
  17.     query.setFirstResult(page * pageSize);
  18.     query.setMaxResults(pageSize);
  19.     return query.getResultList();
  20.   }
  21.   @Override
  22.   @Transactional
  23.   public Customer save(Customer customer) {
  24.     // Is new?
  25.     if (customer.getId() == null) {
  26.       em.persist(customer);
  27.       return customer;
  28.     } else {
  29.       return em.merge(customer);
  30.     }
  31.   }
  32.   @Override
  33.   public List findByLastname(String lastname, int page, int pageSize) {
  34.     TypedQuery query = em.createQuery("select c from Customer c where c.lastname = ?1", Customer.class);
  35.     query.setParameter(1, lastname);
  36.     query.setFirstResult(page * pageSize);
  37.     query.setMaxResults(pageSize);
  38.     return query.getResultList();
  39.   }
  40. }

好吧,首先創(chuàng)建CustomerRepository并消除CRUD方法:

 
 
 
  1. @Transactional(readOnly = true)
  2. public interface CustomerRepository extends JpaRepository { … }
 
 
 
  1. @Repository
  2. @Transactional(readOnly = true)
  3. public class CustomerServiceImpl implements CustomerService {
  4.   @PersistenceContext
  5.   private EntityManager em;
  6.   @Autowired
  7.   private CustomerRepository repository;
  8.   @Override
  9.   public Customer findById(Long id) {
  10.     return repository.findById(id);
  11.   }
  12.   @Override
  13.   public List findAll() {
  14.     return repository.findAll();
  15.   }
  16.   @Override
  17.   public List findAll(int page, int pageSize) {
  18.     TypedQuery query = em.createQuery("select c from Customer c", Customer.class);
  19.     query.setFirstResult(page * pageSize);
  20.     query.setMaxResults(pageSize);
  21.     return query.getResultList();
  22.   }
  23.   @Override
  24.   @Transactional
  25.   public Customer save(Customer customer) {
  26.     return repository.save(customer);
  27.   }
  28.   @Override
  29.   public List findByLastname(String lastname, int page, int pageSize) {
  30.     TypedQuery query = em.createQuery("select c from Customer c where c.lastname = ?1", Customer.class);
  31.     query.setParameter(1, lastname);
  32.     query.setFirstResult(page * pageSize);
  33.     query.setMaxResults(pageSize);
  34.     return query.getResultList();
  35.   }
  36. }

到目前為止,一切都很好。以下兩種方法都可以處理常見(jiàn)的場(chǎng)景:你希望給定查詢能夠分頁(yè)而不是返回全部實(shí)體(比如一頁(yè)10條記錄)。眼下我們通過(guò)兩個(gè)整數(shù)適當(dāng)限制查詢來(lái)實(shí)現(xiàn),但這樣做有兩個(gè)問(wèn)題,兩個(gè)整數(shù)實(shí)際上只代表了一個(gè)方面,這里并沒(méi)有明確這一點(diǎn)。除此之外,結(jié)果我們只返回了一個(gè)簡(jiǎn)單的list,所以我們丟掉了實(shí)際頁(yè)面的元數(shù)據(jù)信息:這是第一頁(yè)嗎?這是最后一頁(yè)嗎?總共有多少頁(yè)?Spring Data提供了一個(gè)抽象包括兩個(gè)接口:Pageable(捕捉分頁(yè)請(qǐng)求)和Page(捕獲結(jié)果以及元信息)。讓我們按照如下方式嘗試添加 findByLastname(…)到存儲(chǔ)庫(kù)接口中并重寫findAll(…)和findByLastname(…)方法:

 
 
 
  1. @Transactional(readOnly = true) 
  2. public interface CustomerRepository extends JpaRepository {
  3.   Page findByLastname(String lastname, Pageable pageable); 
  4. }
 
 
 
  1. @Override 
  2. public Page findAll(Pageable pageable) {
  3.   return repository.findAll(pageable);
  4. }
  5. @Override
  6. public Page findByLastname(String lastname, Pageable pageable) {
  7.   return repository.findByLastname(lastname, pageable); 
  8. }

請(qǐng)確保按照名字的變化對(duì)測(cè)試用例進(jìn)行了適配,這樣它應(yīng)該能正常運(yùn)行。歸結(jié)下來(lái)為兩件事:我們有CRUD方法支持分頁(yè)并且查詢執(zhí)行機(jī)制知道分頁(yè)的參數(shù)。在這個(gè)階段,我們的包裝類實(shí)際上已經(jīng)過(guò)時(shí)了,因?yàn)榭蛻舳艘部梢灾苯诱{(diào)用我們的存儲(chǔ)庫(kù)接口,這樣我們擺脫了整個(gè)的實(shí)現(xiàn)代碼。

總結(jié)

在本文的課程中,我們把為存儲(chǔ)庫(kù)編寫的代碼減少到2個(gè)接口,包含3個(gè)方法一行XML:

 
 
 
  1. @Transactional(readOnly = true) 
  2. public interface CustomerRepository extends JpaRepository {
  3.     Page findByLastname(String lastname, Pageable pageable); 
  4. }
 
 
 
  1. @Transactional(readOnly = true)
  2. public interface AccountRepository extends JpaRepository {
  3.     List findByCustomer(Customer customer); 
  4. }
 
 
 

我們擁有類型安全的CRUD方法、查詢執(zhí)行方法和內(nèi)置的分頁(yè)功能。這不僅適用于基于JPA的存儲(chǔ)庫(kù),而且也適用于非關(guān)系型數(shù)據(jù)庫(kù),這很酷。第一個(gè)支持這些功能的非關(guān)系型數(shù)據(jù)庫(kù)是MongoDB ,它是幾天后發(fā)版的Spring Data Document中的一部分。你將會(huì)獲得Mongo DB版的所有這些特性,而且我們還將支持其它一些數(shù)據(jù)庫(kù)。另外,還有其它一些特性等待我們?nèi)ヌ矫?比如,實(shí)體審計(jì),自定義數(shù)據(jù)訪問(wèn)代碼集成) ,我們會(huì)在后續(xù)的博文中涉及。

英文原文:Getting started with Spring Data JPA

譯文鏈接:http://www.oschina.net/translate/getting-started-with-spring-data-jpa


新聞名稱:開始使用SpringDataJPA
文章起源:http://www.5511xx.com/article/cosighh.html