摘要:與的關(guān)系是什么是官方提出的持久化規(guī)范。它為開發(fā)人員提供了一種對象關(guān)聯(lián)映射工具來管理應(yīng)用中的關(guān)系數(shù)據(jù)。他的出現(xiàn)主要是為了簡化現(xiàn)有的持久化開發(fā)工作和整合技術(shù),結(jié)束現(xiàn)在,,等框架各自為營的局面。定義了在對數(shù)據(jù)庫中的對象處理查詢和事務(wù)運行時的的。
導(dǎo)讀:
在上篇文章中對Spring MVC常用的一些注解做了簡要的說明,在這篇文章中主要對Spring Data JPA 做一個簡要的說明,并附有一個簡單的例子,可以體會到Spring Data JPA 的強大之處。
Spring Data JPA 與JPA的關(guān)系: JPA是什么?JPA(Java Persistence API)是Sun官方提出的Java持久化規(guī)范。它為Java開發(fā)人員提供了一種對象/關(guān)聯(lián)映射工具來管理Java應(yīng)用中的關(guān)系數(shù)據(jù)。他的出現(xiàn)主要是為了簡化現(xiàn)有的持久化開發(fā)工作和整合ORM技術(shù),結(jié)束現(xiàn)在Hibernate,TopLink,JDO等ORM框架各自為營的局面。值得注意的是,JPA是在充分吸收了現(xiàn)有Hibernate,TopLink,JDO等ORM框架的基礎(chǔ)上發(fā)展而來的,具有易于使用,伸縮性強等優(yōu)點。
JPA定義了在對數(shù)據(jù)庫中的對象處理查詢和事務(wù)運行時的EntityManager的API。JPA定義一個對象級查詢語言,JPQL,如果學(xué)習(xí)過Hibernate的話你可以把它看做Hibernate中的Hql語句,以允許從所述數(shù)據(jù)庫中的對象的查詢。
下面是JPA常用的一些解決方案:
EclipseLink (Eclipse) Hibernate (RedHat) Open JPA (Apache) DataNucleus Ebean (SourceForge) TopLink Essentials (Glassfish) TopLink (Oracle) Kodo (Oracle)Spring Data JPA:
你可以把它做做事JPA的超集 類似于 C與C++的關(guān)系,Spring Data JPA可以極大的簡化JPA的寫法,可以在幾乎不用寫實現(xiàn)的情況下,實現(xiàn)對數(shù)據(jù)的訪問和操作。除了CRUD外,還包括如分頁、排序等一些常用的功能。
也就是說Spring Data JPA 在JPA的基礎(chǔ)上提供了更高層次的抽象,幫助我們實現(xiàn)了許多常用的對數(shù)據(jù)庫的操作,從而提高開發(fā)效率。
Spring Data JPA 的一些常用方法在了解Spring Data JPA之前我們首先看一下它為我們提供了那些便利。
1.簡單查詢:面對簡單的查詢時可以通過解析方法名創(chuàng)建查詢或使用使用 @Query 創(chuàng)建查詢語句
比如現(xiàn)在我們有個方法叫做 User findByName(String name),我們可以很清楚的明白它的意思,但有沒有辦法讓ORM框架根據(jù)方法名幫助我們推斷出Sql來呢?在Spring Data JPA中這是可以的,我們只要將我們的接口繼承 org.springframework.data.repository.Repository
public interface UserRepository extends Repository@Query注解查詢 示例:{ User findByName(String name) } @RepositoryDefinition(domainClass = User.class, idClass = Long.class) public interface UserRepository{ User findByName(String name) }
public interface UserRepository extends Repository{ //對于更新操作需要添加@Modifying @Query("from User u where u.name=:name") User findUser(@Param("name") String name); }
當(dāng)然還不止這些Spring Data JPA 還未我們提供了幾個常用的Repository:
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)的方法
通過繼承它們可以獲得更強大的功能,當(dāng)然它們之所能夠運行是因為有了默認的實現(xiàn)類:
@Repository @Transactional(readOnly = true) public class SimpleJpaRepositoryimplements JpaRepository , JpaSpecificationExecutor { }
在查詢的時候,通常需要同時根據(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
NotIn --- 等價于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection
當(dāng)然面對比較復(fù)雜的查詢時,它們就顯得無力了,如果在面對比較復(fù)雜的查詢時,想要有自己的實現(xiàn)方法,只需要通過一個XXXImpl結(jié)尾的實現(xiàn)類即可使用我們自己的實現(xiàn)方法(比如UserRepository接口的同一個包下面建立一個普通類UserRepositoryImpl來表示該類的實現(xiàn)類)。
了解更多:使用 Spring Data JPA 簡化 JPA 開發(fā) - IBM
2.復(fù)雜的查詢面對復(fù)雜的查詢時可以使用本地查詢或JPQL或使用JPA的動態(tài)接口(JpaSpecificationExecutor)
在面對負責(zé)的條件查詢時,需要有條件判斷這個時候方法名推斷就顯得不夠強大了,比如當(dāng)這里有個簡單的例子:“我們要根據(jù)用戶的年齡,地址,性別 查詢用戶信息時”, 在考慮可能存在條件為空的情況下,在使用方法名推斷時我們需要提供8個相應(yīng)的方法,當(dāng)然如果使用流的話有一個findAll方法即可,但是這無疑增大了數(shù)據(jù)庫與發(fā)射生成對象壓力所以并不推薦這種方式,那么在這種情況下如果可以使用判斷進行條件拼接的話,便可以將查詢的方法縮減到一個 這便是以上三種方式的優(yōu)點(一般情況下不推薦 本地查詢)。
JPQL示例:DO:
@Entity public class User extends AbstractPersistable{ private String name; private Integer age; private String AddressCode; @Enumerated(EnumType.ORDINAL) private Sex sex; /**省略get/set**/ }
DAO:
public interface UserCustomRepository { Pagesearch(Integer age, String AddressCode, User.Sex sex, Pageable pageRequest); } public interface UserRepository extends CrudRepository , UserCustomRepository { } public class UserRepositoryImpl implements UserCustomRepository { @PersistenceContext private EntityManager em; @Override public Page search(Integer age, String AddressCode, User.Sex sex, Pageable pageRequest) { String querySql = "select t "; String countSql = "select count(t) "; StringBuffer sqlBuffer = new StringBuffer("from User t where 1=1"); if (null != age) { sqlBuffer.append(" and t.age = :age"); } if (null != AddressCode) { sqlBuffer.append(" and t.AddressCode = :address"); } if (null != sex) { sqlBuffer.append(" and t.sex = :sex"); } querySql += sqlBuffer.toString(); countSql += sqlBuffer.toString(); Query dataQuery = em.createQuery(querySql); Query countQuery = em.createQuery(countSql); if (null != age) { dataQuery.setParameter("age", age); countQuery.setParameter("age", age); } if (null != AddressCode) { dataQuery.setParameter("address", AddressCode); countQuery.setParameter("address", AddressCode); } if (null != sex) { dataQuery.setParameter("sex", sex); countQuery.setParameter("sex", sex); } // 本地查詢方式 // Query query = em.createNativeQuery(sql); // query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(User.class)); Page page = (pageRequest == null ? new PageImpl(dataQuery.getResultList()) : this.readPage(dataQuery, countQuery, pageRequest)); return page; } private Page readPage(Query dataQuery, Query countQuery, Pageable pageable) { dataQuery.setFirstResult(pageable.getOffset()); dataQuery.setMaxResults(pageable.getPageSize()); long totalSize = (long) countQuery.getSingleResult(); List content = totalSize > (long) pageable.getOffset() ? dataQuery.getResultList() : Collections.emptyList(); return new PageImpl(content, pageable, totalSize); } }
Test:
@RunWith(SpringRunner.class) @SpringBootTest @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class SpringBootJpaApplicationTests { @Autowired private UserRepository userRepository; @Test public void contextLoads() { ListJPA的動態(tài)接口(JpaSpecificationExecutor):userList = new ArrayList<>(); for (int i = 0; i < 10; i++) { String name = "name" + i; Integer age = 19 + (i + 1) % 5; String addressCode = "address"; User.Sex sex = i % 2 == 0 ? User.Sex.MAN : User.Sex.WOMAN; User user = new User(name, age, addressCode, sex); System.out.println(JSON.toJSON(user)); userList.add(user); } userRepository.save(userList); } @Test public void search() { int page = 0; int size = 2; Pageable pageable = new PageRequest(page, size); Page pageUser = userRepository.search(null, null, null, pageable); pageUser = userRepository.search(19, null, User.Sex.WOMAN, pageable); System.out.println(JSON.toJSON(pageUser)); } }
只做了簡單的修改
DO:
public interface UserRepository extends CrudRepository, UserCustomRepository, JpaSpecificationExecutor { }
Test:
@RunWith(SpringRunner.class) @SpringBootTest @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class SpringBootJpaApplicationTests { @Autowired private UserRepository userRepository; @Test public void contextLoads() { ListuserList = new ArrayList<>(); for (int i = 0; i < 10; i++) { String name = "name" + i; Integer age = 19 + (i + 1) % 5; String addressCode = "address"; User.Sex sex = i % 2 == 0 ? User.Sex.MAN : User.Sex.WOMAN; User user = new User(name, age, addressCode, sex); System.out.println(JSON.toJSON(user)); userList.add(user); } userRepository.save(userList); } @Test public void search() { int page = 0; int size = 2; Pageable pageable = new PageRequest(page, size); Page pageUser = userRepository.search(null, null, null, pageable); // System.out.println(JSON.toJSON(pageUser)); pageUser = userRepository.search(19, null, User.Sex.WOMAN, pageable); System.out.println(JSON.toJSON(pageUser)); // pageUser = userRepository.search(null, null, null, pageable); // System.out.println(JSON.toJSON(pageUser)); // pageUser = userRepository.search(null, null, null, pageable); // System.out.println(JSON.toJSON(pageUser)); } @Test public void findAll() { int page = 0; int size = 2; Pageable pageable = new PageRequest(page, size); Page pageUser = search(19, null, User.Sex.WOMAN, pageable); System.out.println(JSON.toJSON(pageUser)); } public Page search(final Integer age, final String AddressCode, final User.Sex sex, Pageable pageRequest) { /* 第一種查詢方式 Specification specification = (Root root, CriteriaQuery> query, CriteriaBuilder cb) -> { //創(chuàng)建查詢條件 List predicates = new ArrayList<>(); if (age != null) { predicates.add(cb.equal(root. get("age"), age)); } if (AddressCode != null) { predicates.add(cb.equal(root.get("AddressCode").as(String.class), AddressCode)); } if (sex != null) { predicates.add(cb.equal(root.get("sex").as(User.Sex.class), sex)); } return cb.and(predicates.toArray(new Predicate[predicates.size()])); }; */ //第二種 Specification specification = (Root root, CriteriaQuery> query, CriteriaBuilder cb) -> { //創(chuàng)建查詢條件 List predicates = new ArrayList<>(); if (age != null) { predicates.add(cb.equal(root. get("age"), age)); } if (AddressCode != null) { predicates.add(cb.equal(root.get("AddressCode").as(String.class), AddressCode)); } if (sex != null) { predicates.add(cb.equal(root.get("sex").as(User.Sex.class), sex)); } Predicate[] assetTradingArray = new Predicate[predicates.size()]; predicates.toArray(assetTradingArray); query.where(assetTradingArray);//這種方式使用JPA的API設(shè)置了查詢條件,所以不需要再返回查詢條件Predicate給Spring Data Jpa,故最后return null;即可。 return null; }; return userRepository.findAll(specification, pageRequest); } }
了解更多:純干貨,Spring-data-jpa詳解,全方位介紹。
Spring Data JPA 在Spring-Boot中的使用: 第一步將相關(guān)依賴導(dǎo)入POM文件:第二步配置yml文件(使用了內(nèi)存數(shù)據(jù)庫因此沒有配數(shù)據(jù)源):org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-web com.h2database h2 runtime org.springframework.boot spring-boot-starter-test test com.alibaba fastjson 1.2.23 org.springframework.boot spring-boot-maven-plugin
spring: jpa: show-sql: true properties: hibernate: hbm2ddl: auto: update第三步編寫main函數(shù):
@SpringBootApplication public class SpringBootJpaApplication { public static void main(String[] args) { SpringApplication.run(SpringBootJpaApplication.class, args); } }第四步編寫相關(guān)的Repository:
public interface UserRepository extends CrudRepository相關(guān)邏輯編寫->運行->測試->發(fā)布 學(xué)習(xí)資料收集:, UserCustomRepository, JpaSpecificationExecutor { }
教程:
JPA 使用及介紹 (我起的名字>_<)
博客介紹:
Spring ORM+Hibernate?Out!換 Spring Data JPA 吧!
純干貨,Spring-data-jpa詳解,全方位介紹。 (推薦)
使用 Spring Data JPA 簡化 JPA 開發(fā)
視頻:
尚硅谷Spring Data視頻教程
結(jié)語:Spring Data JPA 的解析方法名創(chuàng)建查詢非常強大,只是聲明持久層的接口,相關(guān)的查詢它就已經(jīng)幫你去做了,讓我想起一個問題框架的終點在哪?是人工智能嗎?
參考文檔:全面闡釋和精彩總結(jié)JPA
Spring Data 系列(二) Spring+JPA入門(集成Hibernate)
Spring Data概念【從零開始學(xué)Spring Boot】
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/66782.html
摘要:作為微服務(wù)的基礎(chǔ)設(shè)施之一,背靠強大的生態(tài)社區(qū),支撐技術(shù)體系。微服務(wù)實踐為系列講座,專題直播節(jié),時長高達小時,包括目前最流行技術(shù),深入源碼分析,授人以漁的方式,幫助初學(xué)者深入淺出地掌握,為高階從業(yè)人員拋磚引玉。 簡介 目前業(yè)界最流行的微服務(wù)架構(gòu)正在或者已被各種規(guī)模的互聯(lián)網(wǎng)公司廣泛接受和認可,業(yè)已成為互聯(lián)網(wǎng)開發(fā)人員必備技術(shù)。無論是互聯(lián)網(wǎng)、云計算還是大數(shù)據(jù),Java平臺已成為全棧的生態(tài)體系,...
摘要:容器自動完成裝載,默認的方式是這部分重點在常用模塊的使用以及的底層實現(xiàn)原理。 對于那些想面試高級 Java 崗位的同學(xué)來說,除了算法屬于比較「天方夜譚」的題目外,剩下針對實際工作的題目就屬于真正的本事了,熱門技術(shù)的細節(jié)和難點成為了主要考察的內(nèi)容。 這里說「天方夜譚」并不是說算法沒用,不切實際,而是想說算法平時其實很少用到,甚至面試官都對自己出的算法題一知半解。 這里總結(jié)打磨了 70 道...
摘要:以前都是用進行數(shù)據(jù)庫的開發(fā),最近學(xué)習(xí)之后發(fā)現(xiàn)顯得更友好,所以我們就一起來了解一下的原理吧。簡單介紹持久性是的一個規(guī)范。它用于在對象和關(guān)系數(shù)據(jù)庫之間保存數(shù)據(jù)。充當(dāng)面向?qū)ο蟮念I(lǐng)域模型和關(guān)系數(shù)據(jù)庫系統(tǒng)之間的橋梁。是標(biāo)識出主鍵是指定主鍵的自增方式。 以前都是用Mybatis進行數(shù)據(jù)庫的開發(fā),最近學(xué)習(xí)Spring Boot之后發(fā)現(xiàn)JPA顯得更友好,所以我們就一起來了解一下JPA的原理吧。 Spr...
閱讀 1215·2021-11-23 09:51
閱讀 1993·2021-10-08 10:05
閱讀 2351·2019-08-30 15:56
閱讀 1910·2019-08-30 15:55
閱讀 2644·2019-08-30 15:55
閱讀 2498·2019-08-30 13:53
閱讀 3510·2019-08-30 12:52
閱讀 1259·2019-08-29 10:57