摘要:與的關系是什么是官方提出的持久化規范。它為開發人員提供了一種對象關聯映射工具來管理應用中的關系數據。他的出現主要是為了簡化現有的持久化開發工作和整合技術,結束現在,,等框架各自為營的局面。定義了在對數據庫中的對象處理查詢和事務運行時的的。
導讀:
在上篇文章中對Spring MVC常用的一些注解做了簡要的說明,在這篇文章中主要對Spring Data JPA 做一個簡要的說明,并附有一個簡單的例子,可以體會到Spring Data JPA 的強大之處。
Spring Data JPA 與JPA的關系: JPA是什么?JPA(Java Persistence API)是Sun官方提出的Java持久化規范。它為Java開發人員提供了一種對象/關聯映射工具來管理Java應用中的關系數據。他的出現主要是為了簡化現有的持久化開發工作和整合ORM技術,結束現在Hibernate,TopLink,JDO等ORM框架各自為營的局面。值得注意的是,JPA是在充分吸收了現有Hibernate,TopLink,JDO等ORM框架的基礎上發展而來的,具有易于使用,伸縮性強等優點。
JPA定義了在對數據庫中的對象處理查詢和事務運行時的EntityManager的API。JPA定義一個對象級查詢語言,JPQL,如果學習過Hibernate的話你可以把它看做Hibernate中的Hql語句,以允許從所述數據庫中的對象的查詢。
下面是JPA常用的一些解決方案:
EclipseLink (Eclipse) Hibernate (RedHat) Open JPA (Apache) DataNucleus Ebean (SourceForge) TopLink Essentials (Glassfish) TopLink (Oracle) Kodo (Oracle)Spring Data JPA:
你可以把它做做事JPA的超集 類似于 C與C++的關系,Spring Data JPA可以極大的簡化JPA的寫法,可以在幾乎不用寫實現的情況下,實現對數據的訪問和操作。除了CRUD外,還包括如分頁、排序等一些常用的功能。
也就是說Spring Data JPA 在JPA的基礎上提供了更高層次的抽象,幫助我們實現了許多常用的對數據庫的操作,從而提高開發效率。
Spring Data JPA 的一些常用方法在了解Spring Data JPA之前我們首先看一下它為我們提供了那些便利。
1.簡單查詢:面對簡單的查詢時可以通過解析方法名創建查詢或使用使用 @Query 創建查詢語句
比如現在我們有個方法叫做 User findByName(String name),我們可以很清楚的明白它的意思,但有沒有辦法讓ORM框架根據方法名幫助我們推斷出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); }
當然還不止這些Spring Data JPA 還未我們提供了幾個常用的Repository:
Repository: 僅僅是一個標識,沒有任何方法,方便Spring自動掃描識別
CrudRepository: 繼承Repository,實現了一組CRUD相關的方法
PagingAndSortingRepository: 繼承CrudRepository,實現了一組分頁排序相關的方法
JpaRepository: 繼承PagingAndSortingRepository,實現一組JPA規范相關的方法
通過繼承它們可以獲得更強大的功能,當然它們之所能夠運行是因為有了默認的實現類:
@Repository @Transactional(readOnly = true) public class SimpleJpaRepositoryimplements JpaRepository , JpaSpecificationExecutor { }
在查詢的時候,通常需要同時根據多個屬性進行查詢,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
NotIn --- 等價于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection
當然面對比較復雜的查詢時,它們就顯得無力了,如果在面對比較復雜的查詢時,想要有自己的實現方法,只需要通過一個XXXImpl結尾的實現類即可使用我們自己的實現方法(比如UserRepository接口的同一個包下面建立一個普通類UserRepositoryImpl來表示該類的實現類)。
了解更多:使用 Spring Data JPA 簡化 JPA 開發 - IBM
2.復雜的查詢面對復雜的查詢時可以使用本地查詢或JPQL或使用JPA的動態接口(JpaSpecificationExecutor)
在面對負責的條件查詢時,需要有條件判斷這個時候方法名推斷就顯得不夠強大了,比如當這里有個簡單的例子:“我們要根據用戶的年齡,地址,性別 查詢用戶信息時”, 在考慮可能存在條件為空的情況下,在使用方法名推斷時我們需要提供8個相應的方法,當然如果使用流的話有一個findAll方法即可,但是這無疑增大了數據庫與發射生成對象壓力所以并不推薦這種方式,那么在這種情況下如果可以使用判斷進行條件拼接的話,便可以將查詢的方法縮減到一個 這便是以上三種方式的優點(一般情況下不推薦 本地查詢)。
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的動態接口(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) -> { //創建查詢條件 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) -> { //創建查詢條件 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設置了查詢條件,所以不需要再返回查詢條件Predicate給Spring Data Jpa,故最后return null;即可。 return null; }; return userRepository.findAll(specification, pageRequest); } }
了解更多:純干貨,Spring-data-jpa詳解,全方位介紹。
Spring Data JPA 在Spring-Boot中的使用: 第一步將相關依賴導入POM文件:第二步配置yml文件(使用了內存數據庫因此沒有配數據源):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函數:
@SpringBootApplication public class SpringBootJpaApplication { public static void main(String[] args) { SpringApplication.run(SpringBootJpaApplication.class, args); } }第四步編寫相關的Repository:
public interface UserRepository extends CrudRepository相關邏輯編寫->運行->測試->發布 學習資料收集:, UserCustomRepository, JpaSpecificationExecutor { }
教程:
JPA 使用及介紹 (我起的名字>_<)
博客介紹:
Spring ORM+Hibernate?Out!換 Spring Data JPA 吧!
純干貨,Spring-data-jpa詳解,全方位介紹。 (推薦)
使用 Spring Data JPA 簡化 JPA 開發
視頻:
尚硅谷Spring Data視頻教程
結語:Spring Data JPA 的解析方法名創建查詢非常強大,只是聲明持久層的接口,相關的查詢它就已經幫你去做了,讓我想起一個問題框架的終點在哪?是人工智能嗎?
參考文檔:全面闡釋和精彩總結JPA
Spring Data 系列(二) Spring+JPA入門(集成Hibernate)
Spring Data概念【從零開始學Spring Boot】
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66782.html
摘要:作為微服務的基礎設施之一,背靠強大的生態社區,支撐技術體系。微服務實踐為系列講座,專題直播節,時長高達小時,包括目前最流行技術,深入源碼分析,授人以漁的方式,幫助初學者深入淺出地掌握,為高階從業人員拋磚引玉。 簡介 目前業界最流行的微服務架構正在或者已被各種規模的互聯網公司廣泛接受和認可,業已成為互聯網開發人員必備技術。無論是互聯網、云計算還是大數據,Java平臺已成為全棧的生態體系,...
摘要:容器自動完成裝載,默認的方式是這部分重點在常用模塊的使用以及的底層實現原理。 對于那些想面試高級 Java 崗位的同學來說,除了算法屬于比較「天方夜譚」的題目外,剩下針對實際工作的題目就屬于真正的本事了,熱門技術的細節和難點成為了主要考察的內容。 這里說「天方夜譚」并不是說算法沒用,不切實際,而是想說算法平時其實很少用到,甚至面試官都對自己出的算法題一知半解。 這里總結打磨了 70 道...
摘要:以前都是用進行數據庫的開發,最近學習之后發現顯得更友好,所以我們就一起來了解一下的原理吧。簡單介紹持久性是的一個規范。它用于在對象和關系數據庫之間保存數據。充當面向對象的領域模型和關系數據庫系統之間的橋梁。是標識出主鍵是指定主鍵的自增方式。 以前都是用Mybatis進行數據庫的開發,最近學習Spring Boot之后發現JPA顯得更友好,所以我們就一起來了解一下JPA的原理吧。 Spr...
閱讀 1201·2021-11-23 09:51
閱讀 1980·2021-10-08 10:05
閱讀 2339·2019-08-30 15:56
閱讀 1900·2019-08-30 15:55
閱讀 2640·2019-08-30 15:55
閱讀 2487·2019-08-30 13:53
閱讀 3498·2019-08-30 12:52
閱讀 1250·2019-08-29 10:57