真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

springdatajpa使用詳解

Spring data簡介:

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、小程序定制開發(fā)、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了新北免費建站歡迎大家使用!

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

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

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

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

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

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

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

Graph Roo AddOn - Roo support for Neo4j

JDBC Extensions - 支持 Oracle RAD、高級隊列和高級數(shù)據(jù)類型

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

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

Guidance - 高級文檔

一、Spring data JPA簡介

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

二、Spring data JPA的功能

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

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

Repository:僅僅是一個標(biāo)識,表明任何繼承它的均為倉庫接口類,方便Spring自動掃描識別?

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

PagingAndSortingRepository:繼承CrudRepository,實現(xiàn)了一組分頁排序相關(guān)的方法?

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

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

三、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 {

}

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

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 users = new ArrayList();

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");// 要想這樣實現(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對象是否存在

public void testIsExist(){

boolean isExist = dao.exists(8);

System.out.println(isExist);

}

@Test//通過id列表來查詢

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àn)這個接口類,就可以完成基本的CRUD操作。因為這個接口會自動為域?qū)ο髣?chuàng)建增刪改查方法,供業(yè)務(wù)層直接使用。

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

@NoRepositoryBean

public interface CrudRepository extends Repository {

S save(S entity);//保存

Iterable save(Iterable entities);//批量保存

T findOne(ID id);//根據(jù)id查詢一個對象

boolean exists(ID id);//判斷對象是否存在

Iterable findAll();//查詢所有的對象

Iterable findAll(Iterable ids);//根據(jù)id列表查詢所有的對象

long count();//計算對象的總個數(shù)

void delete(ID id);//根據(jù)id刪除

void delete(T entity);//刪除對象

void delete(Iterable entities);//批量刪除

void deleteAll();//刪除所有

}

2、PagingAndSortingRepository接口

PagingAndSortingRepository接口繼承了CrudRepository接口。

編寫接口,并繼承PagingAndSortingRepository接口

public interface UserRepositoryWithOrder extends

PagingAndSortingRepository {

?

}

編寫測試類:

@RunWith(SpringJUnit4Cla***unner.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());

}

}

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

@NoRepositoryBean

public interface PagingAndSortingRepository extends CrudRepository {

Iterable findAll(Sort sort);// 不帶分頁的排序

Page findAll(Pageable pageable);// 帶分頁的排序

}

3、JpaRepository接口

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

接口定義如下:

public interface JpaRepository extends PagingAndSortingRepository {

List findAll();//查詢所有對象,不排序

List findAll(Sort sort);//查詢所有對象,并排序

List save(Iterable entities);//批量保存

void flush();//強制緩存與數(shù)據(jù)庫同步

T saveAndFlush(T entity);//保存并強制同步

void deleteInBatch(Iterable entities);//批量刪除

void deleteAllInBatch();//刪除所有

}

4、JpaSpecificationExecutor接口

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

編寫接口如下:

public interface SpecificationExecutorRepository extends CrudRepository,

JpaSpecificationExecutor {

?

}

Service類:

@Service

public class SpecificationExecutorRepositoryManager {

@Autowired

private SpecificationExecutorRepository dao;

/**

* 描述:根據(jù)name來查詢用戶

*/

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來查詢用戶

*/

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);

}

});

}

/**

* 描述:排序和分頁操作

*/

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();

}

});

}

}

測試類:

@RunWith(SpringJUnit4Cla***unner.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 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接口

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

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

四、Spring data JPA的查詢

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

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

編寫接口,如下:

/**

?* 描述:自定義查詢,當(dāng)Spring Data JPA無法提供時,需要自定義接口,此時可以使用這種方式

?*/

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表示第一個參數(shù)

User findUserByEmail(String email);

/**

* 描述:可以通過@Modifying和@Query來實現(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注解里面有一個配置clearAutomatically

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

測試類:

@RunWith(SpringJUnit4Cla***unner.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);

}

}

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

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

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

編寫接口:

public interface FindUserByNamedQueryRepository extends JpaRepository {

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 {

/**

* 注意:此處必須要給這個實體類定義一個唯一標(biāo)識,否則會報異常

*/

@Id

@GeneratedValue

private Integer id;

}

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

測試類:

@RunWith(SpringJUnit4Cla***unner.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、通過解析方法名創(chuàng)建查詢

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

編寫接口:

public interface SimpleConditionQueryRepository extends JpaRepository {

/**

* 說明:按照Spring data 定義的規(guī)則,查詢方法以find|read|get開頭

? ? ?* 涉及條件查詢時,條件的屬性用條件關(guān)鍵字連接,要注意的是:條件屬性首字母需大寫

*/

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name = :name and u.email = :email

* 參數(shù)名大寫,條件名首字母大寫,并且接口名中參數(shù)出現(xiàn)的順序必須和參數(shù)列表中的參數(shù)順序一致

*/

User findByNameAndEmail(String name, String email);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name = ?1 or u.password = ?2

*/

List findByNameOrPassword(String name, String password);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id between ?1 and ?2

*/

List findByIdBetween(Integer start, Integer end);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id < ?1

*/

List findByIdLessThan(Integer end);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id > ?1

*/

List findByIdGreaterThan(Integer start);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name is null

*/

List findByNameIsNull();

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name is not null

*/

List findByNameIsNotNull();

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name like ?1

*/

List findByNameLike(String name);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name not like ?1

*/

List findByNameNotLike(String name);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.password = ?1 order by u.id desc

*/

List findByPasswordOrderByIdDesc(String password);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.name <> ?1

*/

List findByNameNot(String name);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id in ?1

*/

List findByIdIn(List ids);

/**

* 注:此處這個接口相當(dāng)于發(fā)送了一條SQL:select u from User u where u.id not in ?1

*/

List findByIdNotIn(List ids);

}

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

@RunWith(SpringJUnit4Cla***unner.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 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

*/

@Test

public void testFindByIdLessThan(){

List 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));

}

}

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

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

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

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

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

Between --- 等價于 SQL 中的 between 關(guān)鍵字,比如 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 userList) ,方法的參數(shù)可以是 Collection 類型,也可以是數(shù)組或者不定長參數(shù)

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

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

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

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

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

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

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

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

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

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


網(wǎng)站標(biāo)題:springdatajpa使用詳解
網(wǎng)站地址:http://weahome.cn/article/igdsge.html

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部