最近2018中文字幕在日韩欧美国产成人片_国产日韩精品一区二区在线_在线观看成年美女黄网色视频_国产精品一区三区五区_国产精彩刺激乱对白_看黄色黄大色黄片免费_人人超碰自拍cao_国产高清av在线_亚洲精品电影av_日韩美女尤物视频网站

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

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
springdatajpa怎么用

這篇文章將為大家詳細(xì)講解有關(guān)spring data jpa怎么用,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

十載的磴口網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。網(wǎng)絡(luò)營(yíng)銷(xiāo)推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整磴口建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。成都創(chuàng)新互聯(lián)公司從事“磴口網(wǎng)站設(shè)計(jì)”,“磴口網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

前言:

Spring data簡(jiǎn)介:

Spring Data是一個(gè)用于簡(jiǎn)化數(shù)據(jù)庫(kù)訪問(wèn),并支持云服務(wù)的開(kāi)源框架。其主要目標(biāo)是使得對(duì)數(shù)據(jù)的訪問(wèn)變得方便快捷,并支持map-reduce框架和云計(jì)算數(shù)據(jù)服務(wù)。 Spring Data 包含多個(gè)子項(xiàng)目:

Commons - 提供共享的基礎(chǔ)框架,適合各個(gè)子項(xiàng)目使用,支持跨數(shù)據(jù)庫(kù)持久化

JPA - 簡(jiǎn)化創(chuàng)建 JPA 數(shù)據(jù)訪問(wèn)層和跨存儲(chǔ)的持久層功能

Hadoop - 基于 Spring 的 Hadoop 作業(yè)配置和一個(gè) POJO 編程模型的 MapReduce 作業(yè)

Key-Value  - 集成了 redis 和 Riak ,提供多個(gè)常用場(chǎng)景下的簡(jiǎn)單封裝

Document - 集成文檔數(shù)據(jù)庫(kù):CouchDB 和 MongoDB 并提供基本的配置映射和資料庫(kù)支持

Graph - 集成 Neo4j 提供強(qiáng)大的基于 POJO 的編程模型

Graph Roo AddOn - Roo support for Neo4j

JDBC Extensions - 支持 Oracle RAD、高級(jí)隊(duì)列和高級(jí)數(shù)據(jù)類(lèi)型

Mapping - 基于 Grails 的提供對(duì)象映射框架,支持不同的數(shù)據(jù)庫(kù)

Examples - 示例程序、文檔和圖數(shù)據(jù)庫(kù)

Guidance - 高級(jí)文檔

一、Spring data JPA簡(jiǎn)介

Spring data JPA是Spring在ORM框架,以及JPA規(guī)范的基礎(chǔ)上,封裝的一套JPA應(yīng)用框架,并提供了一整套的數(shù)據(jù)訪問(wèn)層解決方案。

二、Spring data JPA的功能

Spring data JPA的功能非常的強(qiáng)大,這里我們先跳過(guò)環(huán)境搭建這一步,來(lái)一睹Spring data JPA的“芳容”。

Spring data JPA提供給用戶使用的,主要有以下幾個(gè)接口:

  1. Repository:僅僅是一個(gè)標(biāo)識(shí),表明任何繼承它的均為倉(cāng)庫(kù)接口類(lèi),方便Spring自動(dòng)掃描識(shí)別

  2. CrudRepository:繼承Repository,實(shí)現(xiàn)了一組CRUD相關(guān)的方法

  3. PagingAndSortingRepository:繼承CrudRepository,實(shí)現(xiàn)了一組分頁(yè)排序相關(guān)的方法

  4. JpaRepository:繼承PagingAndSortingRepository,實(shí)現(xiàn)一組JPA規(guī)范相關(guān)的方法

  5. JpaSpecificationExecutor:比較特殊,不屬于Repository體系,實(shí)現(xiàn)一組JPA Criteria查詢相關(guān)的方法。

三、Spring data JPA的接口

1、CrudRepository接口

建立一個(gè)Entity類(lèi):

@Entity 
@Table(name="USER") 
public class User { 
  @Id 
  @GeneratedValue 
  private Integer id;    
  //賬號(hào) 
  private String account; 
  //姓名 
  private String name;    
  //密碼 
  private String password;    
  // 郵箱 
  private String email; 
}

編寫(xiě)接口,并繼承CrudRepository接口:

public interface UserRepository extends CrudRepository {    
}

編寫(xiě)測(cè)試類(lèi)(為了更直觀的看到效果,所有測(cè)試類(lèi)都沒(méi)有使用斷言,直接使用的打印語(yǔ)句):

public class UserRepositoryTest { 
  @Autowired 
  private UserRepository dao; 
   
  @Test//保存 
  public void testSave(){ 
    User user = new User(); 
    user.setName("chhliu"); 
    user.setAccount("10000"); 
    user.setEmail("[email protected]"); 
    user.setPassword("123456"); 
    dao.save(user); 
  } 
   
  @Test//批量保存 
  public void testSave1(){ 
    List users = new ArrayList(); 
    User user = new User(); 
    user.setName("tanjie"); 
    user.setAccount("10000"); 
    user.setEmail("[email protected]"); 
    user.setPassword("123456"); 
    users.add(user); 
    user = new User(); 
    user.setName("esdong"); 
    user.setAccount("10000"); 
    user.setEmail("[email protected]"); 
    user.setPassword("123456"); 
    users.add(user); 
    user = new User(); 
    user.setName("qinhongfei"); 
    user.setAccount("10000"); 
    user.setEmail("[email protected]"); 
    user.setPassword("123456"); 
    users.add(user); 
    user = new User(); 
    user.setName("huizhang"); 
    user.setAccount("10000"); 
    user.setEmail("[email protected]"); 
    user.setPassword("123456"); 
    users.add(user); 
    user = new User(); 
    user.setName("caican"); 
    user.setAccount("10000"); 
    user.setEmail("[email protected]"); 
    user.setPassword("123456"); 
    users.add(user); 
    dao.save(users); 
  } 
   
  @Test//更新 
  public void testUpdate(){ 
    User user = dao.findOne(1); 
    user.setPassword("123890");// 要想這樣實(shí)現(xiàn)更新的功能,需要在service層加上@Transaction事物注解 
  } 
   
  @Test//刪除 
  public void testDelete(){ 
    dao.delete(2); 
  } 
   
  @Test//查詢所有 
  public void testFindAll(){ 
    List users = (List) dao.findAll(); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  @Test//判斷指定的id對(duì)象是否存在 
  public void testIsExist(){ 
    boolean isExist = dao.exists(8); 
    System.out.println(isExist); 
  } 
   
  @Test//通過(guò)id列表來(lái)查詢 
  public void testFindUserByIds(){ 
    List listIds = new ArrayList(); 
    listIds.add(2); 
    listIds.add(4); 
    listIds.add(7); 
    List users = (List) dao.findAll(listIds); 
    System.out.println(JSON.toJSONString(users)); 
  } 
}

大家可以看出,到這里,我就只寫(xiě)了一個(gè)接口類(lèi),并沒(méi)有實(shí)現(xiàn)這個(gè)接口類(lèi),就可以完成基本的CRUD操作。因?yàn)檫@個(gè)接口會(huì)自動(dòng)為域?qū)ο髣?chuàng)建增刪改查方法,供業(yè)務(wù)層直接使用。

該接口的定義如下,總共提供了11個(gè)方法,基本上可以滿足簡(jiǎn)單的CRUD操作以及批量操作:

@NoRepositoryBean 
public interface CrudRepository extends Repository { 
   S save(S entity);//保存 
   Iterable save(Iterable entities);//批量保存 
  T findOne(ID id);//根據(jù)id查詢一個(gè)對(duì)象 
  boolean exists(ID id);//判斷對(duì)象是否存在 
  Iterable findAll();//查詢所有的對(duì)象 
  Iterable findAll(Iterable ids);//根據(jù)id列表查詢所有的對(duì)象 
  long count();//計(jì)算對(duì)象的總個(gè)數(shù) 
  void delete(ID id);//根據(jù)id刪除 
  void delete(T entity);//刪除對(duì)象 
  void delete(Iterable entities);//批量刪除 
  void deleteAll();//刪除所有 
}

2、PagingAndSortingRepository接口

PagingAndSortingRepository接口繼承了CrudRepository接口。

編寫(xiě)接口,并繼承PagingAndSortingRepository接口

public interface UserRepositoryWithOrder extends 
    PagingAndSortingRepository {  
}

編寫(xiě)測(cè)試類(lèi):

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext-config.xml" }) 
@TransactionConfiguration(defaultRollback = false) 
@Transactional 
public class UserRepositoryWithOrderTest { 
  @Autowired 
  private UserRepositoryWithOrder dao; 
   
  @Test 
  public void testOrder(){ 
    Sort sort = new Sort(Direction.DESC, "id"); 
    Pageable pageable = new PageRequest(0, 5, sort); 
    Page page = dao.findAll(pageable); 
    System.out.println(JSON.toJSONString(page)); 
    System.out.println(page.getSize()); 
  } 
}

只要繼承了這個(gè)接口,Spring data JPA就已經(jīng)為你提供了分頁(yè)和排序的功能了。該接口的定義如下,主要提供了兩個(gè)方法,供使用,其中T是要操作的實(shí)體類(lèi),ID是實(shí)體類(lèi)主鍵的類(lèi)型

@NoRepositoryBean 
public interface PagingAndSortingRepository extends CrudRepository { 
  Iterable findAll(Sort sort);// 不帶分頁(yè)的排序 
  Page findAll(Pageable pageable);// 帶分頁(yè)的排序 
}

3、JpaRepository接口

如果業(yè)務(wù)需要即提供CRUD操作,又需要提供分頁(yè)以及排序功能,那么就可以直接繼承這個(gè)接口。該接口繼承了PagingAndSortingRepository接口。

接口定義如下:

public interface JpaRepository extends PagingAndSortingRepository { 
  List findAll();//查詢所有對(duì)象,不排序 
  List findAll(Sort sort);//查詢所有對(duì)象,并排序 
   List save(Iterable entities);//批量保存 
  void flush();//強(qiáng)制緩存與數(shù)據(jù)庫(kù)同步 
  T saveAndFlush(T entity);//保存并強(qiáng)制同步 
  void deleteInBatch(Iterable entities);//批量刪除 
  void deleteAllInBatch();//刪除所有 
}

4、JpaSpecificationExecutor接口

該接口提供了對(duì)JPA Criteria查詢的支持。注意,這個(gè)接口很特殊,不屬于Repository體系,而Spring data JPA不會(huì)自動(dòng)掃描識(shí)別,所以會(huì)報(bào)找不到對(duì)應(yīng)的Bean,我們只需要繼承任意一個(gè)繼承了Repository的子接口或直接繼承Repository接口,Spring data JPA就會(huì)自動(dòng)掃描識(shí)別,進(jìn)行統(tǒng)一的管理。

編寫(xiě)接口如下:

public interface SpecificationExecutorRepository extends CrudRepository, 
    JpaSpecificationExecutor {  
}

Service類(lèi):

@Service 
public class SpecificationExecutorRepositoryManager { 
  @Autowired 
  private SpecificationExecutorRepository dao; 
  /** 
   * 描述:根據(jù)name來(lái)查詢用戶 
   */ 
  public User findUserByName(final String name){ 
    return dao.findOne(new Specification() { 
       
      @Override 
      public Predicate toPredicate(Root root, CriteriaQuery query, 
          CriteriaBuilder cb) { 
        Predicate predicate = cb.equal(root.get("name"), name); 
        return predicate; 
      } 
    }); 
  } 
   
  /** 
   * 描述:根據(jù)name和email來(lái)查詢用戶 
   */ 
  public User findUserByNameAndEmail(final String name, final String email){ 
    return dao.findOne(new Specification() { 
       
      @Override 
      public Predicate toPredicate(Root root, 
          CriteriaQuery query, CriteriaBuilder cb) { 
        List list = new ArrayList(); 
        Predicate predicate1 = cb.equal(root.get("name"), name); 
        Predicate predicate2 = cb.equal(root.get("email"), email); 
        list.add(predicate1); 
        list.add(predicate2); 
        // 注意此處的處理 
        Predicate[] p = new Predicate[list.size()]; 
        return cb.and(list.toArray(p)); 
      } 
    }); 
  } 
   
  /** 
   * 描述:組合查詢 
   */ 
  public User findUserByUser(final User userVo){ 
    return dao.findOne(new Specification() { 
       
      @Override 
      public Predicate toPredicate(Root root, 
          CriteriaQuery query, CriteriaBuilder cb) { 
        Predicate predicate = cb.equal(root.get("name"), userVo.getName()); 
        cb.and(predicate, cb.equal(root.get("email"), userVo.getEmail())); 
        cb.and(predicate, cb.equal(root.get("password"), userVo.getPassword())); 
        return predicate; 
      } 
    }); 
  } 
   
  /** 
   * 描述:范圍查詢in方法,例如查詢用戶id在[2,10]中的用戶 
   */ 
  public List findUserByIds(final List ids){ 
    return dao.findAll(new Specification() { 
 
      @Override 
      public Predicate toPredicate(Root root, 
          CriteriaQuery query, CriteriaBuilder cb) { 
        return root.in(ids); 
      } 
    }); 
  } 
   
  /** 
   * 描述:范圍查詢gt方法,例如查詢用戶id大于9的所有用戶 
   */ 
  public List findUserByGtId(final int id){ 
    return dao.findAll(new Specification() { 
 
      @Override 
      public Predicate toPredicate(Root root, 
          CriteriaQuery query, CriteriaBuilder cb) { 
        return cb.gt(root.get("id").as(Integer.class), id); 
      } 
    }); 
  } 
   
  /** 
   * 描述:范圍查詢lt方法,例如查詢用戶id小于10的用戶 
   */ 
  public List findUserByLtId(final int id){ 
    return dao.findAll(new Specification() { 
 
      @Override 
      public Predicate toPredicate(Root root, 
          CriteriaQuery query, CriteriaBuilder cb) { 
        return cb.lt(root.get("id").as(Integer.class), id); 
      } 
    }); 
  } 
   
  /** 
   * 描述:范圍查詢between方法,例如查詢id在3和10之間的用戶 
   */ 
  public List findUserBetweenId(final int start, final int end){ 
    return dao.findAll(new Specification() { 
 
      @Override 
      public Predicate toPredicate(Root root, 
          CriteriaQuery query, CriteriaBuilder cb) { 
        return cb.between(root.get("id").as(Integer.class), start, end); 
      } 
    }); 
  } 
   
  /** 
   * 描述:排序和分頁(yè)操作 
   */ 
  public Page findUserAndOrder(final int id){ 
    Sort sort = new Sort(Direction.DESC, "id"); 
    return dao.findAll(new Specification() { 
 
      @Override 
      public Predicate toPredicate(Root root, 
          CriteriaQuery query, CriteriaBuilder cb) { 
        return cb.gt(root.get("id").as(Integer.class), id); 
      } 
    }, new PageRequest(0, 5, sort)); 
  } 
   
  /** 
   * 描述:只有排序操作 
   */ 
  public List findUserAndOrderSecondMethod(final int id){ 
    return dao.findAll(new Specification() { 
 
      @Override 
      public Predicate toPredicate(Root root, 
          CriteriaQuery query, CriteriaBuilder cb) { 
        cb.gt(root.get("id").as(Integer.class), id); 
        query.orderBy(cb.desc(root.get("id").as(Integer.class))); 
        return query.getRestriction(); 
      } 
    }); 
  } 
}

測(cè)試類(lèi):

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext-config.xml" }) 
@TransactionConfiguration(defaultRollback = false) 
@Transactional 
public class SpecificationExecutorRepositoryManagerTest { 
  @Autowired 
  private SpecificationExecutorRepositoryManager manager; 
  @Test 
  public void testFindUserByName(){ 
    User user = manager.findUserByName("chhliu"); 
    System.out.println(JSON.toJSONString(user)); 
  } 
   
  @Test 
  public void testFindUserByNameAndEmail(){ 
    User user = manager.findUserByNameAndEmail("chhliu", "[email protected]"); 
    System.out.println(JSON.toJSONString(user)); 
  } 
   
  @Test 
  public void testFindUserByUserVo(){ 
    User user = new User(); 
    user.setName("chhliu"); 
    user.setEmail("[email protected]"); 
    User u = manager.findUserByUser(user); 
    System.out.println(JSON.toJSONString(u)); 
  } 
   
  @Test 
  public void testFindUserByIds(){ 
    List users = manager.findUserByIds(new ArrayList(Arrays.asList(1,3,5,6))); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  @Test 
  public void testFindUserByGtId(){ 
    List users = manager.findUserByGtId(5); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  @Test 
  public void testFindUserByLtId(){ 
    List users = manager.findUserByLtId(5); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  @Test 
  public void testFindUserBetweenId(){ 
    List users = manager.findUserBetweenId(4, 9); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  @Test 
  public void testFindUserAndOrder(){ 
    Page users = manager.findUserAndOrder(1); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  @Test 
  public void testFindUserAndOrderSecondMethod(){ 
    List users = manager.findUserAndOrderSecondMethod(1); 
    System.out.println(JSON.toJSONString(users)); 
  } 
}

5、Repository接口

這個(gè)接口是最基礎(chǔ)的接口,只是一個(gè)標(biāo)志性的接口,沒(méi)有定義任何的方法,那這個(gè)接口有什么用了?既然Spring data JPA提供了這個(gè)接口,自然是有它的用處,例如,我們有一部分方法是不想對(duì)外提供的,比如我們只想提供增加和修改方法,不提供刪除方法,那么前面的幾個(gè)接口都是做不到的,這個(gè)時(shí)候,我們就可以繼承這個(gè)接口,然后將CrudRepository接口里面相應(yīng)的方法拷貝到Repository接口就可以了。

總結(jié):上述五個(gè)接口,開(kāi)發(fā)者到底該如何選擇?其實(shí)依據(jù)很簡(jiǎn)單,根據(jù)具體的業(yè)務(wù)需求,選擇其中之一。因?yàn)楦鱾€(gè)接口之間并不存在功能強(qiáng)弱的問(wèn)題。

四、Spring data JPA的查詢

1、使用 @Query 創(chuàng)建查詢

@Query 注解的使用非常簡(jiǎn)單,只需在聲明的方法上面標(biāo)注該注解,同時(shí)提供一個(gè) JP QL 查詢語(yǔ)句即可。很多開(kāi)發(fā)者在創(chuàng)建 JP QL 時(shí)喜歡使用命名參數(shù)來(lái)代替位置編號(hào),@Query 也對(duì)此提供了支持。JP QL 語(yǔ)句中通過(guò)": 變量"的格式來(lái)指定參數(shù),同時(shí)在方法的參數(shù)前面使用 @Param 將方法參數(shù)與 JP QL 中的命名參數(shù)對(duì)應(yīng)。此外,開(kāi)發(fā)者也可以通過(guò)使用 @Query 來(lái)執(zhí)行一個(gè)更新操作,為此,我們需要在使用 @Query 的同時(shí),用 @Modifying 來(lái)將該操作標(biāo)識(shí)為修改查詢,這樣框架最終會(huì)生成一個(gè)更新的操作,而非查詢操作。

編寫(xiě)接口,如下:

/** 
 * 描述:自定義查詢,當(dāng)Spring Data JPA無(wú)法提供時(shí),需要自定義接口,此時(shí)可以使用這種方式 
 */ 
public interface UserDefineBySelf extends JpaRepository { 
  /** 
   * 命名參數(shù) 
   * 描述:推薦使用這種方法,可以不用管參數(shù)的位置 
   */ 
  @Query("select u from User u where u.name = :name") 
  User findUserByName(@Param("name") String name); 
   
  /** 
   * 索引參數(shù) 
   * 描述:使用?占位符 
   */ 
  @Query("select u from User u where u.email = ?1")// 1表示第一個(gè)參數(shù) 
  User findUserByEmail(String email); 
   
  /** 
   * 描述:可以通過(guò)@Modifying和@Query來(lái)實(shí)現(xiàn)更新 
   * 注意:Modifying queries的返回值只能為void或者是int/Integer 
   */ 
  @Modifying 
  @Query("update User u set u.name = :name where u.id = :id") 
  int updateUserById(@Param("name") String name, @Param("id") int id); 
}

注:@Modifying注解里面有一個(gè)配置clearAutomatically

它說(shuō)的是可以清除底層持久化上下文,就是entityManager這個(gè)類(lèi),我們知道jpa底層實(shí)現(xiàn)會(huì)有二級(jí)緩存,也就是在更新完數(shù)據(jù)庫(kù)后,如果后面去用這個(gè)對(duì)象,你再去查這個(gè)對(duì)象,這個(gè)對(duì)象是在一級(jí)緩存,但是并沒(méi)有跟數(shù)據(jù)庫(kù)同步,這個(gè)時(shí)候用clearAutomatically=true,就會(huì)刷新hibernate的一級(jí)緩存了, 不然你在同一接口中,更新一個(gè)對(duì)象,接著查詢這個(gè)對(duì)象,那么你查出來(lái)的這個(gè)對(duì)象還是之前的沒(méi)有更新之前的狀態(tài)

測(cè)試類(lèi):

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext-config.xml" }) 
@TransactionConfiguration(defaultRollback = false) 
@Transactional 
public class UserDefineBySelfTest { 
  @Autowired 
  private UserDefineBySelf dao; 
   
  @Test 
  public void testFindUserByName(){ 
    User user = dao.findUserByName("chhliu"); 
    Assert.assertEquals("chhliu", user.getName()); 
    System.out.println(user.getName()); 
  } 
   
  @Test 
  public void testFindUserByEmail(){ 
    User user = dao.findUserByEmail("[email protected]"); 
    Assert.assertEquals("chhliu", user.getName()); 
    System.out.println(user.getName()); 
  } 
   
  @Test 
  public void testUpdateUserById(){ 
    dao.updateUserById("tanjie", 4); 
  } 
}

從測(cè)試代碼可以看出,我們同樣只定義了接口,沒(méi)有任何的實(shí)現(xiàn)類(lèi),但是卻實(shí)現(xiàn)了我們所需要的功能。

2、使用@NamedQueries創(chuàng)建查詢

命名查詢是 JPA 提供的一種將查詢語(yǔ)句從方法體中獨(dú)立出來(lái),以供多個(gè)方法共用的功能。Spring Data JPA 對(duì)命名查詢也提供了很好的支持。用戶只需要按照 JPA 規(guī)范在 orm.xml 文件或者在代碼中使用 @NamedQuery(或 @NamedNativeQuery)定義好查詢語(yǔ)句,唯一要做的就是為該語(yǔ)句命名時(shí),需要滿足”DomainClass.methodName()”的 命名規(guī)則。

編寫(xiě)接口:

public interface FindUserByNamedQueryRepository extends JpaRepository { 
  User findUserWithName(@Param("name") String name); 
}

編寫(xiě)類(lèi):

@Entity 
@NamedQueries(value={ 
    @NamedQuery(name="User.findUserWithName",query="select u from User u where u.name = :name") 
}) 
// 注意:此處如果是多個(gè)方法,那么需要使用@NamedQueries,如果只有一個(gè)方法,則可以使用@NamedQuery,寫(xiě)法如下:@NamedQuery(name="User.findUserWithName",query="select u from User u where u.name = :name") 
public class FindUserByNamedQuery { 
  /** 
   * 注意:此處必須要給這個(gè)實(shí)體類(lèi)定義一個(gè)唯一標(biāo)識(shí),否則會(huì)報(bào)異常 
   */ 
  @Id 
  @GeneratedValue 
  private Integer id; 
}

注意:文中標(biāo)記為紅色的部分,需要一一對(duì)應(yīng),否則不滿足JPA 的規(guī)范。

測(cè)試類(lèi):

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext-config.xml" }) 
@TransactionConfiguration(defaultRollback = false) 
@Transactional 
public class FindUserByNamedQueryRepositoryTest { 
  @Autowired 
  private FindUserByNamedQueryRepository dao; 
   
  @Test 
  public void testFindUserByName(){ 
    User user = dao.findUserWithName("caican"); 
    System.out.println(JSON.toJSONString(user)); 
  } 
}

3、通過(guò)解析方法名創(chuàng)建查詢

顧名思義,就是根據(jù)方法的名字,就能創(chuàng)建查詢,也許初聽(tīng)起來(lái),感覺(jué)很不可思議,等測(cè)試后才發(fā)現(xiàn),原來(lái)一切皆有可能。

編寫(xiě)接口:

public interface SimpleConditionQueryRepository extends JpaRepository { 
  /** 
   * 說(shuō)明:按照Spring data 定義的規(guī)則,查詢方法以find|read|get開(kāi)頭 
   * 涉及條件查詢時(shí),條件的屬性用條件關(guān)鍵字連接,要注意的是:條件屬性首字母需大寫(xiě) 
   */    
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name = :name and u.email = :email 
   * 參數(shù)名大寫(xiě),條件名首字母大寫(xiě),并且接口名中參數(shù)出現(xiàn)的順序必須和參數(shù)列表中的參數(shù)順序一致 
   */ 
  User findByNameAndEmail(String name, String email); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name = ?1 or u.password = ?2 
   */ 
  List findByNameOrPassword(String name, String password); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id between ?1 and ?2 
   */ 
  List findByIdBetween(Integer start, Integer end); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id < ?1 
   */ 
  List findByIdLessThan(Integer end); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id > ?1 
   */ 
  List findByIdGreaterThan(Integer start); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name is null 
   */ 
  List findByNameIsNull(); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name is not null 
   */ 
  List findByNameIsNotNull(); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name like ?1 
   */ 
  List findByNameLike(String name); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name not like ?1 
   */ 
  List findByNameNotLike(String name); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.password = ?1 order by u.id desc 
   */ 
  List findByPasswordOrderByIdDesc(String password); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name <> ?1 
   */ 
  List findByNameNot(String name); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id in ?1 
   */ 
  List findByIdIn(List ids); 
   
  /** 
   * 注:此處這個(gè)接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id not in ?1 
   */ 
  List findByIdNotIn(List ids); 
}

測(cè)試類(lèi)(注釋部分為實(shí)際發(fā)送的sql語(yǔ)句):

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext-config.xml" }) 
@TransactionConfiguration(defaultRollback = false) 
@Transactional 
public class SimpleConditionQueryRepositoryTest { 
  @Autowired 
  private SimpleConditionQueryRepository dao; 
   
  /** 
   * select 
    user0_.id as id0_, 
    user0_.account as account0_, 
    user0_.email as email0_, 
    user0_.name as name0_, 
    user0_.password as password0_ 
  from 
    USER user0_ 
  where 
    user0_.name=? 
    and user0_.email=? limit ? 
   */ 
  @Test 
  public void testFindUserByNameAndEmail(){ 
    User user = dao.findByNameAndEmail("chhliu", "[email protected]"); 
    System.out.println(JSON.toJSONString(user)); 
  } 
   
  /** 
   * select 
    user0_.id as id1_, 
    user0_.account as account1_, 
    user0_.email as email1_, 
    user0_.name as name1_, 
    user0_.password as password1_ 
  from 
    USER user0_ 
  where 
    user0_.name=? 
    or user0_.password=? 
   */ 
  @Test 
  public void testFindUserByNameOrPassword(){ 
    List users = dao.findByNameOrPassword("chhliu", "123456"); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id1_, 
    user0_.account as account1_, 
    user0_.email as email1_, 
    user0_.name as name1_, 
    user0_.password as password1_ 
  from 
    USER user0_ 
  where 
    user0_.id between ? and ? 
   */ 
  @Test 
  public void testFindByIdBetween(){ 
    List users = dao.findByIdBetween(5, 8); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id1_, 
    user0_.account as account1_, 
    user0_.email as email1_, 
    user0_.name as name1_, 
    user0_.password as password1_ 
  from 
    USER user0_ 
  where 
    user0_.id users = dao.findByIdLessThan(4); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id0_, 
    user0_.account as account0_, 
    user0_.email as email0_, 
    user0_.name as name0_, 
    user0_.password as password0_ 
  from 
    USER user0_ 
  where 
    user0_.id>? 
   */ 
  @Test 
  public void testFindByIdGreaterThan(){ 
    List users = dao.findByIdGreaterThan(6); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id0_, 
    user0_.account as account0_, 
    user0_.email as email0_, 
    user0_.name as name0_, 
    user0_.password as password0_ 
  from 
    USER user0_ 
  where 
    user0_.name is null 
   */ 
  @Test 
  public void testFindByNameIsNull(){ 
    List users = dao.findByNameIsNull(); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id1_, 
    user0_.account as account1_, 
    user0_.email as email1_, 
    user0_.name as name1_, 
    user0_.password as password1_ 
  from 
    USER user0_ 
  where 
    user0_.name is not null 
   */ 
  @Test 
  public void testFindByNameIsNotNull(){ 
    List users = dao.findByNameIsNotNull(); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id1_, 
    user0_.account as account1_, 
    user0_.email as email1_, 
    user0_.name as name1_, 
    user0_.password as password1_ 
  from 
    USER user0_ 
  where 
    user0_.name like ? 
   */ 
  @Test 
  public void testFindByNameLike(){ 
    List users = dao.findByNameLike("chhliu"); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id0_, 
    user0_.account as account0_, 
    user0_.email as email0_, 
    user0_.name as name0_, 
    user0_.password as password0_ 
  from 
    USER user0_ 
  where 
    user0_.name not like ? 
   */ 
  @Test 
  public void testFindByNameNotLike(){ 
    List users = dao.findByNameNotLike("chhliu"); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id0_, 
    user0_.account as account0_, 
    user0_.email as email0_, 
    user0_.name as name0_, 
    user0_.password as password0_ 
  from 
    USER user0_ 
  where 
    user0_.password=? 
  order by 
    user0_.id desc 
   */ 
  @Test 
  public void testFindByPasswordOrderByIdDesc(){ 
    List users = dao.findByPasswordOrderByIdDesc("123456"); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id1_, 
    user0_.account as account1_, 
    user0_.email as email1_, 
    user0_.name as name1_, 
    user0_.password as password1_ 
  from 
    USER user0_ 
  where 
    user0_.name<>? 
   */ 
  @Test 
  public void testFindByNameNot(){ 
    List users = dao.findByNameNot("chhliu"); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id1_, 
    user0_.account as account1_, 
    user0_.email as email1_, 
    user0_.name as name1_, 
    user0_.password as password1_ 
  from 
    USER user0_ 
  where 
    user0_.id in ( 
      ? , ? , ? , ? 
    ) 
   */ 
  @Test 
  public void testFindByIdIn(){ 
    List users = dao.findByIdIn(new ArrayList(Arrays.asList(3,4,6,8))); 
    System.out.println(JSON.toJSONString(users)); 
  } 
   
  /** 
   * select 
    user0_.id as id0_, 
    user0_.account as account0_, 
    user0_.email as email0_, 
    user0_.name as name0_, 
    user0_.password as password0_ 
  from 
    USER user0_ 
  where 
    user0_.id not in ( 
      ? , ? , ? , ? 
    ) 
   */ 
  @Test 
  public void testFindByIdNotIn(){ 
    List users = dao.findByIdNotIn(new ArrayList(Arrays.asList(3,4,6,8))); 
    System.out.println(JSON.toJSONString(users)); 
  } 
}

這里,我們只定義了一個(gè)接口,接口里面只有方法,但是沒(méi)有任何的實(shí)現(xiàn),卻完成了各種操作。

看到這里,估計(jì)很多人都會(huì)問(wèn),Spring data JPA是怎么做到的了?原來(lái),框架在進(jìn)行方法名解析時(shí),會(huì)先把方法名多余的前綴截取掉,比如 find、findBy、read、readBy、get、getBy,然后對(duì)剩下部分進(jìn)行解析。并且如果方法的最后一個(gè)參數(shù)是 Sort 或者 Pageable 類(lèi)型,也會(huì)提取相關(guān)的信息,以便按規(guī)則進(jìn)行排序或者分頁(yè)查詢。在創(chuàng)建查詢時(shí),我們通過(guò)在方法名中使用屬性名稱來(lái)表達(dá),比如 findByIdIn()??蚣茉诮馕鲈摲椒〞r(shí),首先剔除 findBy,然后對(duì)剩下的屬性進(jìn)行解析。

在查詢時(shí),通常需要同時(shí)根據(jù)多個(gè)屬性進(jìn)行查詢,且查詢的條件也格式各樣(大于某個(gè)值、在某個(gè)范圍等等),Spring Data JPA 為此提供了一些表達(dá)條件查詢的關(guān)鍵字,大致如下:

And --- 等價(jià)于 SQL 中的 and 關(guān)鍵字,比如 findByUsernameAndPassword(String user, Striang pwd)

Or --- 等價(jià)于 SQL 中的 or 關(guān)鍵字,比如 findByUsernameOrAddress(String user, String addr)

Between --- 等價(jià)于 SQL 中的 between 關(guān)鍵字,比如 findBySalaryBetween(int max, int min)

LessThan --- 等價(jià)于 SQL 中的 "<",比如 findBySalaryLessThan(int max)

GreaterThan --- 等價(jià)于 SQL 中的">",比如 findBySalaryGreaterThan(int min)

IsNull --- 等價(jià)于 SQL 中的 "is null",比如 findByUsernameIsNull()

IsNotNull --- 等價(jià)于 SQL 中的 "is not null",比如 findByUsernameIsNotNull()

NotNull --- 與 IsNotNull 等價(jià)

Like --- 等價(jià)于 SQL 中的 "like",比如 findByUsernameLike(String user)

NotLike --- 等價(jià)于 SQL 中的 "not like",比如 findByUsernameNotLike(String user)

OrderBy ---等價(jià)于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user)

Not --- 等價(jià)于 SQL 中的 "! =",比如 findByUsernameNot(String user)

In --- 等價(jià)于 SQL 中的 "in",比如 findByUsernameIn(Collection userList) ,方法的參數(shù)可以是 Collection 類(lèi)型,也可以是數(shù)組或者不定長(zhǎng)參數(shù)

NotIn --- 等價(jià)于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection userList) ,方法的參數(shù)可以是 Collection 類(lèi)型,也可以是數(shù)組或者不定長(zhǎng)參數(shù)

五、創(chuàng)建查詢的順序

Spring Data JPA 在為接口創(chuàng)建代理對(duì)象時(shí),如果發(fā)現(xiàn)同時(shí)存在多種上述情況可用,它該優(yōu)先采用哪種策略呢?為此, 提供了 query-lookup-strategy 屬性,用以指定查找的順序。它有如下三個(gè)取值:

create --- 通過(guò)解析方法名字來(lái)創(chuàng)建查詢。即使有符合的命名查詢,或者方法通過(guò) @Query 指定的查詢語(yǔ)句,都將會(huì)被忽略。

create-if-not-found --- 如果方法通過(guò) @Query 指定了查詢語(yǔ)句,則使用該語(yǔ)句實(shí)現(xiàn)查詢;如果沒(méi)有,則查找是否定義了符合條件的命名查詢,如果找到,則使用該命名查詢;如果兩者都沒(méi)有找到,則通過(guò)解析方 法名字來(lái)創(chuàng)建查詢。這是 query-lookup-strategy 屬性的默認(rèn)值。

use-declared-query --- 如果方法通過(guò) @Query 指定了查詢語(yǔ)句,則使用該語(yǔ)句實(shí)現(xiàn)查詢;如果沒(méi)有,則查找是否定義了符合條件的命名查詢,如果找到,則使用該命名查詢;如果兩者都沒(méi)有找到,則拋出異常。

六、Spring Data JPA 對(duì)事務(wù)的支持

細(xì)心的讀者也許從上面的代碼中看出了一些端倪,我們?cè)谑褂肧pring data JPA的時(shí)候,只是定義了接口,在使用的時(shí)候,直接注入就可以了,并沒(méi)有做與事物相關(guān)的任何處理,但實(shí)際上,事物已經(jīng)起到效果了,這又是為什么了?

默認(rèn)情況下,Spring Data JPA 實(shí)現(xiàn)的方法都是使用事務(wù)的。針對(duì)查詢類(lèi)型的方法,其等價(jià)于 @Transactional(readOnly=true);增刪改類(lèi)型的方法,等價(jià)于 @Transactional??梢钥闯?,除了將查詢的方法設(shè)為只讀事務(wù)外,其他事務(wù)屬性均采用默認(rèn)值。

如果用戶覺(jué)得有必要,可以在接口方法上使用 @Transactional 顯式指定事務(wù)屬性,該值覆蓋 Spring Data JPA 提供的默認(rèn)值。同時(shí),開(kāi)發(fā)者也可以在業(yè)務(wù)層方法上使用 @Transactional 指定事務(wù)屬性,這主要針對(duì)一個(gè)業(yè)務(wù)層方法多次調(diào)用持久層方法的情況。持久層的事務(wù)會(huì)根據(jù)設(shè)置的事務(wù)傳播行為來(lái)決定是掛起業(yè)務(wù)層事務(wù)還是加入業(yè)務(wù)層的事務(wù)。

關(guān)于“spring data jpa怎么用”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。


網(wǎng)頁(yè)標(biāo)題:springdatajpa怎么用
當(dāng)前URL:http://fisionsoft.com.cn/article/jdigio.html