摘要:我將舉幾個栗子,來詳細的說一下我自己在使用多表復雜查詢的場景和想法。名字手機號這是一個單表的多條件復雜查詢,由于是在幾個屬性中進行篩選,其中的屬性的個數不知道有多少個,所以只需要利用查詢就可以很方便的實現這個需求。
最近工作中由于要求只能用hibernate+jpa 與數據庫進行交互,在簡單查詢中,jpa繼承CrudRepository接口 ,然后利用jpa的方法命名規范進行jpql查詢,然而在進行復雜查詢時,需要繼承JpaSpecificationExecutor接口 利用Specification 進行復雜查詢,由于我自己就遇到了這一問題,查了好多資料,雖然有方法,但是都沒有一個詳細的講解,以至于知道方法而不能很好的利用jpa復雜查詢的方便之處。我將舉幾個栗子,來詳細的說一下我自己在使用jpa多表復雜查詢的場景和想法。
栗子1:
以一個實體類User中的幾個屬性進行篩選。
1. 名字 2. ID 3. 手機號
這是一個單表的多條件復雜查詢,由于是在幾個屬性中進行篩選,其中的屬性的個數不知道有多少個,所以只需要利用Specification 查詢就可以很方便的實現這個需求。 下面請看代碼:
場景:頁面上通過條件篩選,查詢用戶列表
這里有3個條件 在頁面上我設置的id分別為searchName,searchId,searchMobile。 由于這個是user表 所以userRepository 繼承JpaSpecificationExecutor接口,隨后我創建了一個封裝條件的類
public class PageParam{ private Integer pageSize = 10; private Integer pageNumber = 1; private String searchName; private String searchMobile; private String searchId; }
由于我這個方法是直接分頁的 所以pageNumber 和pageSize 也可以直接寫入到這個類中,用于方便接收參數,主要是對下面3個參數的封裝
Specificationspecification = new Specification () { @Override public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) { List list = new ArrayList (); if (StringUtils.isNotBlank(searchName)) { list.add(cb.like(root.get("name").as(String.class), "%" + searchName + "%")); } if (StringUtils.isNotBlank(searchId)) { list.add(cb.equal(root.get("id").as(Long.class), searchId)); } if (StringUtils.isNotBlank(searchMobile)) { list.add(cb.like(root.get("mobile").as(String.class), "%" + searchMobile + "%")); } Predicate[] p = new Predicate[list.size()]; return cb.and(list.toArray(p)); }; };
這里因為都是一個表,所以只要root.get(‘N ‘)這個N對應所要查的 屬性的名字就好,屬性名 屬性名 重要的事情說三遍。
再接下來看一組多表的查詢
栗子2:
這里有4張表
public class Living { Long id; @ManyToOne @JsonIgnore @JoinColumn(name = "actorId", foreignKey = @ForeignKey(name = "none", value =ConstraintMode.NO_CONSTRAINT)) public Actor actor; @ManyToOne @JsonIgnore @JoinColumn(name = "regionId", foreignKey = @ForeignKey(name = "none", value =ConstraintMode.NO_CONSTRAINT)) public Region region; } public class Actor { Long id; @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY) @JoinColumn(name = "actorId") @org.hibernate.annotations.ForeignKey(name = "none") Listlivings = new ArrayList<>(); @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY) @org.hibernate.annotations.ForeignKey(name = "none") @JoinColumn(name = "userDetailId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) UserDetail userDetail; @Column(nullable = false) @Enumerated(value = EnumType.ORDINAL) ActorType actorType = ActorType.A; public enum ActorType{ A,B,C } } public class UserDetail { Long id; @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY) @org.hibernate.annotations.ForeignKey(name = "none") @JoinColumn(name = "actorId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) Actor actor; String truename; } public class Region { Long id; String name; @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY) @JoinColumn(name = "regionId") @org.hibernate.annotations.ForeignKey(name = "none") List Livings; }
現在要根據userdetai 種的 sex actor中的actortype 還有 region的id 為條件查詢出滿足條件的living。
public class PageParam{ private Integer pageSize = 10; private Integer pageNumber = 1; private Sex sex; private ActorType actortype; private Long cityid;
首先我還是封裝了這樣一個類,但是這里的泛型 我是直接給到了想要的查詢結果的泛型,接下來 因為這里涉及到了一個 多表的查詢 所以上面的單表查詢的例子 已經不適合這個查詢了,但是Criteria 的join方法 給我們提供了一個模式
Specificationspecification = new Specification () { @Override public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) { List list = new ArrayList (); if (null!=sex) { Join join = root.join("actor", JoinType.LEFT); list.add(cb.equal(join.get("userDetail").get("sex"), sex )); } if (null!=actortype) { Join join = root.join("actor", JoinType.LEFT); list.add(cb.equal(join.get("actorType"), actortype)); } if (null!=cityid) { Join join = root.join("region", JoinType.LEFT); list.add(cb.equal(join.get("id"), cityid)); } //Join join = root.join("bs", JoinType.LEFT); //list.add(cb.equal(join.get("c").get("id"), id)); Predicate[] p = new Predicate[list.size()]; return cb.and(list.toArray(p)); }; };
這里是我對條件進行的封裝。jpa 的多條件查詢 主要是根據Criteria 為我們提供的方法封裝條件,然后根據 給條件定義的位置,再生成sql語句,之后完成查詢。
不得不說的地方,在這個多表的查詢中以下面這句為例
Joinjoin = root.join("actor", JoinType.LEFT); list.add(cb.equal(join.get("userDetail").get("sex"), sex ));
jointype.LEFT主要是說最終的這個屬性 是在哪個表中, 而前面的 “actor” 則表示 從living表中 查詢的 第一步的查詢,比如我給出的例子 是要查詢出 living 中的 actor 然后是actor 中的userdetail 之后才是 userdetail中的 sex屬性 所以下面的join.get(“userDetail”).get(“sex”) ,這里就是get出相應的屬性,一直到你得到想要的屬性為止。 接下來的兩個屬性 也同理,
許多人多jpa 有很大的誤解,認為jpa 的多表,多條件復雜查詢,不如mybatis的查詢,在之前我也是這么覺得,但自從通過jpa 實現了這個多表多條件的復雜查詢之后,我覺得hibernate的復雜查詢 不遜于mybatis ,尤其是對sql 語句不是很精通的 碼農,雖然hibernate的門檻較高可jpa 恰恰降低了hibernate 所需要的門檻,希望大家可以通過我的經驗,更方便的與數據庫進行交互。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75774.html
摘要:要是緊急排查個問題,媽蛋雖然有很多好處,比如和底層的無關。你的公司如果有,是不允許你亂用的。 知乎看到問題《SpringBoot開發使用Mybatis還是Spring Data JPA??》,順手一答,討論激烈。我實在搞不懂spring data jpa為啥選了hibernate作為它的實現,是Gavin King的裙帶關系么?DAO層搞來搞去,從jdbc到hibernate,從top...
摘要:對關聯另外的實體關聯查詢另外一張表的多個實體如部門實體對應的對象中需要關聯多個子部門實體。對于關聯一個或多個實體的情況,一般通過的實現無的實現方案不寫,不通過的,要更優雅的實現關聯的自動綁定,一個主流的方案就是類似的注解了。 上一篇無SQL實現單表CRUD中我們已經通過Mybatis-plus插件的通用Mapper實現了單表的CRUD的無SQL化,已經可以有效減少Mybatis的代碼量...
摘要:不管是還是,表之間的連接查詢,被映射為實體類之間的關聯關系,這樣,如果兩個實體類之間沒有實現關聯關系,你就不能把兩個實體或者表起來查詢。 因為項目需要選擇數據持久化框架,看了一下主要幾個流行的和不流行的框架,對于復雜業務系統,最終的結論是,JOOQ是總體上最好的,可惜不是完全免費,最終選擇JDBC Template。 Hibernate和Mybatis是使用最多的兩個主流框架,而JOO...
摘要:忽略該字段的映射省略創建數據訪問層接口,需要繼承,第一個泛型參數是實體對象的名稱,第二個是主鍵類型。 SpringBoot 是為了簡化 Spring 應用的創建、運行、調試、部署等一系列問題而誕生的產物,自動裝配的特性讓我們可以更好的關注業務本身而不是外部的XML配置,我們只需遵循規范,引入相關的依賴就可以輕易的搭建出一個 WEB 工程 上一篇介紹了Spring JdbcTempl...
閱讀 1635·2021-10-09 09:44
閱讀 2769·2021-10-08 10:04
閱讀 2461·2021-09-26 09:55
閱讀 3831·2021-09-22 10:02
閱讀 3304·2019-08-29 17:08
閱讀 1064·2019-08-29 15:08
閱讀 2952·2019-08-26 13:52
閱讀 3267·2019-08-26 13:34