亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

spring data jpa使用詳解(推薦)

2024-07-14 08:39:45
字體:
來源:轉載
供稿:網友

使用Spring data JPA開發已經有一段時間了,這期間學習了一些東西,也遇到了一些問題,在這里和大家分享一下。

前言:

Spring data簡介:

Spring Data是一個用于簡化數據庫訪問,并支持云服務的開源框架。其主要目標是使得對數據的訪問變得方便快捷,并支持map-reduce框架和云計算數據服務。 Spring Data 包含多個子項目:

Commons - 提供共享的基礎框架,適合各個子項目使用,支持跨數據庫持久化

JPA - 簡化創建 JPA 數據訪問層和跨存儲的持久層功能

Hadoop - 基于 Spring 的 Hadoop 作業配置和一個 POJO 編程模型的 MapReduce 作業

Key-Value  - 集成了 Redis 和 Riak ,提供多個常用場景下的簡單封裝

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

Graph - 集成 Neo4j 提供強大的基于 POJO 的編程模型

Graph Roo AddOn - Roo support for Neo4j

JDBC Extensions - 支持 Oracle RAD、高級隊列和高級數據類型

Mapping - 基于 Grails 的提供對象映射框架,支持不同的數據庫

Examples - 示例程序、文檔和圖數據庫

Guidance - 高級文檔

一、Spring data JPA簡介

Spring data JPA是Spring在ORM框架,以及JPA規范的基礎上,封裝的一套JPA應用框架,并提供了一整套的數據訪問層解決方案。

二、Spring data JPA的功能

Spring data JPA的功能非常的強大,這里我們先跳過環境搭建這一步,來一睹Spring data JPA的“芳容”。

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

  1. Repository:僅僅是一個標識,表明任何繼承它的均為倉庫接口類,方便Spring自動掃描識別
  2. CrudRepository:繼承Repository,實現了一組CRUD相關的方法
  3. PagingAndSortingRepository:繼承CrudRepository,實現了一組分頁排序相關的方法
  4. JpaRepository:繼承PagingAndSortingRepository,實現一組JPA規范相關的方法
  5. JpaSpecificationExecutor:比較特殊,不屬于Repository體系,實現一組JPA Criteria查詢相關的方法。

三、Spring data JPA的接口

1、CrudRepository接口

建立一個Entity類:

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

編寫接口,并繼承CrudRepository接口:

public interface UserRepository extends CrudRepository<User, Integer> {    } 

編寫測試類(為了更直觀的看到效果,所有測試類都沒有使用斷言,直接使用的打印語句):

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

大家可以看出,到這里,我就只寫了一個接口類,并沒有實現這個接口類,就可以完成基本的CRUD操作。因為這個接口會自動為域對象創建增刪改查方法,供業務層直接使用。

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

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

2、PagingAndSortingRepository接口

PagingAndSortingRepository接口繼承了CrudRepository接口。

編寫接口,并繼承PagingAndSortingRepository接口

public interface UserRepositoryWithOrder extends     PagingAndSortingRepository<User, Integer> {  } 

編寫測試類:

@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<User> page = dao.findAll(pageable);     System.out.println(JSON.toJSONString(page));     System.out.println(page.getSize());   } } 

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

@NoRepositoryBean public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {   Iterable<T> findAll(Sort sort);// 不帶分頁的排序   Page<T> findAll(Pageable pageable);// 帶分頁的排序 } 

3、JpaRepository接口

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

接口定義如下:

public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {   List<T> findAll();//查詢所有對象,不排序   List<T> findAll(Sort sort);//查詢所有對象,并排序   <S extends T> List<S> save(Iterable<S> entities);//批量保存   void flush();//強制緩存與數據庫同步   T saveAndFlush(T entity);//保存并強制同步   void deleteInBatch(Iterable<T> entities);//批量刪除   void deleteAllInBatch();//刪除所有 } 

4、JpaSpecificationExecutor接口

該接口提供了對JPA Criteria查詢的支持。注意,這個接口很特殊,不屬于Repository體系,而Spring data JPA不會自動掃描識別,所以會報找不到對應的Bean,我們只需要繼承任意一個繼承了Repository的子接口或直接繼承Repository接口,Spring data JPA就會自動掃描識別,進行統一的管理。

編寫接口如下:

public interface SpecificationExecutorRepository extends CrudRepository<User, Integer>,     JpaSpecificationExecutor<User> {  } 

Service類:

@Service public class SpecificationExecutorRepositoryManager {   @Autowired   private SpecificationExecutorRepository dao;   /**    * 描述:根據name來查詢用戶    */   public User findUserByName(final String name){     return dao.findOne(new Specification<User>() {              @Override       public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query,           CriteriaBuilder cb) {         Predicate predicate = cb.equal(root.get("name"), name);         return predicate;       }     });   }      /**    * 描述:根據name和email來查詢用戶    */   public User findUserByNameAndEmail(final String name, final String email){     return dao.findOne(new Specification<User>() {              @Override       public Predicate toPredicate(Root<User> root,           CriteriaQuery<?> query, CriteriaBuilder cb) {         List<Predicate> list = new ArrayList<Predicate>();         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<User>() {              @Override       public Predicate toPredicate(Root<User> 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<User> findUserByIds(final List<Integer> ids){     return dao.findAll(new Specification<User>() {        @Override       public Predicate toPredicate(Root<User> root,           CriteriaQuery<?> query, CriteriaBuilder cb) {         return root.in(ids);       }     });   }      /**    * 描述:范圍查詢gt方法,例如查詢用戶id大于9的所有用戶    */   public List<User> findUserByGtId(final int id){     return dao.findAll(new Specification<User>() {        @Override       public Predicate toPredicate(Root<User> root,           CriteriaQuery<?> query, CriteriaBuilder cb) {         return cb.gt(root.get("id").as(Integer.class), id);       }     });   }      /**    * 描述:范圍查詢lt方法,例如查詢用戶id小于10的用戶    */   public List<User> findUserByLtId(final int id){     return dao.findAll(new Specification<User>() {        @Override       public Predicate toPredicate(Root<User> root,           CriteriaQuery<?> query, CriteriaBuilder cb) {         return cb.lt(root.get("id").as(Integer.class), id);       }     });   }      /**    * 描述:范圍查詢between方法,例如查詢id在3和10之間的用戶    */   public List<User> findUserBetweenId(final int start, final int end){     return dao.findAll(new Specification<User>() {        @Override       public Predicate toPredicate(Root<User> root,           CriteriaQuery<?> query, CriteriaBuilder cb) {         return cb.between(root.get("id").as(Integer.class), start, end);       }     });   }      /**    * 描述:排序和分頁操作    */   public Page<User> findUserAndOrder(final int id){     Sort sort = new Sort(Direction.DESC, "id");     return dao.findAll(new Specification<User>() {        @Override       public Predicate toPredicate(Root<User> root,           CriteriaQuery<?> query, CriteriaBuilder cb) {         return cb.gt(root.get("id").as(Integer.class), id);       }     }, new PageRequest(0, 5, sort));   }      /**    * 描述:只有排序操作    */   public List<User> findUserAndOrderSecondMethod(final int id){     return dao.findAll(new Specification<User>() {        @Override       public Predicate toPredicate(Root<User> 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();       }     });   } } 

測試類:

@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", "chhliu@.com");     System.out.println(JSON.toJSONString(user));   }      @Test   public void testFindUserByUserVo(){     User user = new User();     user.setName("chhliu");     user.setEmail("chhliu@.com");     User u = manager.findUserByUser(user);     System.out.println(JSON.toJSONString(u));   }      @Test   public void testFindUserByIds(){     List<User> users = manager.findUserByIds(new ArrayList<Integer>(Arrays.asList(1,3,5,6)));     System.out.println(JSON.toJSONString(users));   }      @Test   public void testFindUserByGtId(){     List<User> users = manager.findUserByGtId(5);     System.out.println(JSON.toJSONString(users));   }      @Test   public void testFindUserByLtId(){     List<User> users = manager.findUserByLtId(5);     System.out.println(JSON.toJSONString(users));   }      @Test   public void testFindUserBetweenId(){     List<User> users = manager.findUserBetweenId(4, 9);     System.out.println(JSON.toJSONString(users));   }      @Test   public void testFindUserAndOrder(){     Page<User> users = manager.findUserAndOrder(1);     System.out.println(JSON.toJSONString(users));   }      @Test   public void testFindUserAndOrderSecondMethod(){     List<User> users = manager.findUserAndOrderSecondMethod(1);     System.out.println(JSON.toJSONString(users));   } } 

5、Repository接口

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

總結:上述五個接口,開發者到底該如何選擇?其實依據很簡單,根據具體的業務需求,選擇其中之一。因為各個接口之間并不存在功能強弱的問題。

四、Spring data JPA的查詢

1、使用 @Query 創建查詢

@Query 注解的使用非常簡單,只需在聲明的方法上面標注該注解,同時提供一個 JP QL 查詢語句即可。很多開發者在創建 JP QL 時喜歡使用命名參數來代替位置編號,@Query 也對此提供了支持。JP QL 語句中通過": 變量"的格式來指定參數,同時在方法的參數前面使用 @Param 將方法參數與 JP QL 中的命名參數對應。此外,開發者也可以通過使用 @Query 來執行一個更新操作,為此,我們需要在使用 @Query 的同時,用 @Modifying 來將該操作標識為修改查詢,這樣框架最終會生成一個更新的操作,而非查詢操作。

編寫接口,如下:

/**  * 描述:自定義查詢,當Spring Data JPA無法提供時,需要自定義接口,此時可以使用這種方式  */ public interface UserDefineBySelf extends JpaRepository<User, Integer> {   /**    * 命名參數    * 描述:推薦使用這種方法,可以不用管參數的位置    */   @Query("select u from User u where u.name = :name")   User findUserByName(@Param("name") String name);      /**    * 索引參數    * 描述:使用?占位符    */   @Query("select u from User u where u.email = ?1")// 1表示第一個參數   User findUserByEmail(String email);      /**    * 描述:可以通過@Modifying和@Query來實現更新    * 注意: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注解里面有一個配置clearAutomatically

它說的是可以清除底層持久化上下文,就是entityManager這個類,我們知道jpa底層實現會有二級緩存,也就是在更新完數據庫后,如果后面去用這個對象,你再去查這個對象,這個對象是在一級緩存,但是并沒有跟數據庫同步,這個時候用clearAutomatically=true,就會刷新hibernate的一級緩存了, 不然你在同一接口中,更新一個對象,接著查詢這個對象,那么你查出來的這個對象還是之前的沒有更新之前的狀態

測試類:

@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("chhliu@.com");     Assert.assertEquals("chhliu", user.getName());     System.out.println(user.getName());   }      @Test   public void testUpdateUserById(){     dao.updateUserById("tanjie", 4);   } } 

從測試代碼可以看出,我們同樣只定義了接口,沒有任何的實現類,但是卻實現了我們所需要的功能。

2、使用@NamedQueries創建查詢

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

編寫接口:

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

編寫類:

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

注意:文中標記為紅色的部分,需要一一對應,否則不滿足JPA 的規范。

測試類:

@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、通過解析方法名創建查詢

顧名思義,就是根據方法的名字,就能創建查詢,也許初聽起來,感覺很不可思議,等測試后才發現,原來一切皆有可能。

編寫接口:

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

測試類(注釋部分為實際發送的sql語句):

@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", "chhliu@.com");     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<User> 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<User> 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<?    */   @Test   public void testFindByIdLessThan(){     List<User> 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<User> 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<User> 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<User> 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<User> 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<User> 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<User> 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<User> 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<User> users = dao.findByIdIn(new ArrayList<Integer>(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<User> users = dao.findByIdNotIn(new ArrayList<Integer>(Arrays.asList(3,4,6,8)));     System.out.println(JSON.toJSONString(users));   } } 

這里,我們只定義了一個接口,接口里面只有方法,但是沒有任何的實現,卻完成了各種操作。

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

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

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

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

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

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

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

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

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

NotNull --- 與 IsNotNull 等價

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

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

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

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

In --- 等價于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的參數可以是 Collection 類型,也可以是數組或者不定長參數

NotIn --- 等價于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的參數可以是 Collection 類型,也可以是數組或者不定長參數

五、創建查詢的順序

Spring Data JPA 在為接口創建代理對象時,如果發現同時存在多種上述情況可用,它該優先采用哪種策略呢?為此,<jpa:repositories> 提供了 query-lookup-strategy 屬性,用以指定查找的順序。它有如下三個取值:

create --- 通過解析方法名字來創建查詢。即使有符合的命名查詢,或者方法通過 @Query 指定的查詢語句,都將會被忽略。

create-if-not-found --- 如果方法通過 @Query 指定了查詢語句,則使用該語句實現查詢;如果沒有,則查找是否定義了符合條件的命名查詢,如果找到,則使用該命名查詢;如果兩者都沒有找到,則通過解析方 法名字來創建查詢。這是 query-lookup-strategy 屬性的默認值。

use-declared-query --- 如果方法通過 @Query 指定了查詢語句,則使用該語句實現查詢;如果沒有,則查找是否定義了符合條件的命名查詢,如果找到,則使用該命名查詢;如果兩者都沒有找到,則拋出異常。

六、Spring Data JPA 對事務的支持

細心的讀者也許從上面的代碼中看出了一些端倪,我們在使用Spring data JPA的時候,只是定義了接口,在使用的時候,直接注入就可以了,并沒有做與事物相關的任何處理,但實際上,事物已經起到效果了,這又是為什么了?

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

如果用戶覺得有必要,可以在接口方法上使用 @Transactional 顯式指定事務屬性,該值覆蓋 Spring Data JPA 提供的默認值。同時,開發者也可以在業務層方法上使用 @Transactional 指定事務屬性,這主要針對一個業務層方法多次調用持久層方法的情況。持久層的事務會根據設置的事務傳播行為來決定是掛起業務層事務還是加入業務層的事務。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久精品亚洲一区| 日韩电影中文字幕av| 国产精品日韩在线| 九九久久久久久久久激情| 九九久久久久99精品| 国内久久久精品| 992tv成人免费影院| 日韩av免费看| 欧美精品videofree1080p| 日韩av手机在线观看| 亚洲精品国产精品自产a区红杏吧| 日韩av在线网页| 欧美洲成人男女午夜视频| 97成人精品区在线播放| 91九色国产视频| 欧美视频第一页| 91国产精品91| 亚洲女同精品视频| 国产亚洲视频中文字幕视频| 精品香蕉在线观看视频一| 欧美国产日韩精品| 国产精品视频白浆免费视频| 国产精品99久久久久久久久| 在线午夜精品自拍| 亚洲色图欧美制服丝袜另类第一页| 精品久久久久久国产91| 日韩国产一区三区| 久久精品国产久精国产思思| 国产精品福利在线观看| 欧美日韩一区二区三区在线免费观看| 国产成人+综合亚洲+天堂| 91国产一区在线| 日韩一级黄色av| 国内精品久久久久久中文字幕| 综合国产在线视频| 九九热精品视频在线播放| 久久视频免费在线播放| 亚洲欧美资源在线| 自拍偷拍亚洲精品| 久久久噜噜噜久久中文字免| 国产一区二区三区在线观看视频| 久久久伊人日本| 久久久久久久久久久亚洲| 欧美巨乳美女视频| 亚洲色图日韩av| 欧美国产极速在线| 亚洲第一二三四五区| 欧美激情中文网| 久久久女人电视剧免费播放下载| 亚洲欧美制服第一页| 亚洲精品综合久久中文字幕| 亚洲色图50p| 91精品国产综合久久香蕉的用户体验| 欧美一级高清免费| 亚洲国产成人久久| 日韩中文字幕免费视频| 美女视频久久黄| 欧美激情久久久久| 久久成人精品电影| 日韩精品高清在线观看| 狠狠综合久久av一区二区小说| 欧美成人精品不卡视频在线观看| 欧美视频在线看| 欧美在线观看www| 亚洲欧美日韩精品久久亚洲区| 国产精品日韩久久久久| 亚洲国产精品电影| 久久久久这里只有精品| 91精品国产高清久久久久久91| 精品福利在线视频| 成人妇女免费播放久久久| 日韩亚洲精品电影| 日韩视频第一页| 亚洲欧美成人精品| 欧美性猛交xxxx久久久| 一本色道久久综合狠狠躁篇的优点| 久久亚洲综合国产精品99麻豆精品福利| 亚洲加勒比久久88色综合| 中文字幕亚洲综合久久筱田步美| 亚洲欧洲午夜一线一品| 尤物九九久久国产精品的特点| 人人澡人人澡人人看欧美| 日韩美女在线看| 亚洲va男人天堂| 亚洲性猛交xxxxwww| 国产小视频91| 欧美激情在线观看视频| 欧美日韩一区二区精品| 日韩av不卡电影| 国产精品人成电影| 久久久久久久999精品视频| 亚洲人成网在线播放| 欧美午夜精品在线| 日韩欧美福利视频| 欧美电影《睫毛膏》| 欧美在线亚洲一区| 欧美第一黄网免费网站| 热re99久久精品国产66热| 中文字幕亚洲欧美日韩高清| 在线电影av不卡网址| 成人免费高清完整版在线观看| 亚洲国产精品推荐| 国产精品中文字幕久久久| 中文字幕亚洲欧美在线| 色伦专区97中文字幕| 欧美成人小视频| 亚洲精品久久久久久久久久久| 欧美一级片在线播放| 国产精品美女视频网站| 91精品国产综合久久男男| 成人福利视频在线观看| 亚洲欧美综合v| 国产成人精品免费视频| 国产福利精品视频| 精品久久香蕉国产线看观看gif| 国产精品久久久av久久久| 伊人伊人伊人久久| 欧美久久精品一级黑人c片| 97精品视频在线| 亚洲一区二区三区四区视频| 亚洲人成网7777777国产| 成人福利视频在线观看| 欧美成人免费视频| 亚洲色图综合久久| 国产亚洲免费的视频看| 亚洲美女视频网| 欧美成人中文字幕在线| 国产精品久久久久久久久久东京| 欧美成人免费一级人片100| 精品欧美一区二区三区| 97超级碰碰碰| 亚洲女同性videos| 国产欧美日韩免费| 亚洲人成电影在线| 日韩小视频网址| 成人午夜在线视频一区| 亚洲国产精品va在看黑人| 欧美国产亚洲精品久久久8v| 日韩精品视频中文在线观看| 亚洲色图欧美制服丝袜另类第一页| 亚洲国产又黄又爽女人高潮的| 欧美二区在线播放| 中文字幕亚洲一区| 亚洲精品www久久久久久广东| 国产精品女视频| 91久久综合亚洲鲁鲁五月天| 欧美精品在线播放| 欧美性xxxx在线播放| 高清亚洲成在人网站天堂| 日本精品中文字幕| 亚洲精品v欧美精品v日韩精品| 亚洲欧美国产另类| 国产精品久久久久久久久久尿| 日韩电影在线观看永久视频免费网站| 日韩日本欧美亚洲| 亚洲综合在线中文字幕| 日本欧美爱爱爱| 97色在线视频观看| 亚洲老司机av| 亚洲欧美日韩在线一区| 亚洲精品丝袜日韩| 精品日韩中文字幕| 欧美日韩一区二区三区在线免费观看| 日韩av在线影院|