<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在前面章節中,我們介紹了DMQ 和 @Query兩種查詢方法,除此之外,還有QueryByExampleExecutor查詢方法。
QueryByExampleExecutor是一種使用者友好的查詢技術,具有簡單的介面,它允許動態建立,並且不需要填寫包含欄位名稱的查詢。
public interface QueryByExampleExecutor<T> { // 根據實體查詢條件、查詢一個物件 <S extends T> Optional<S> findOne(Example<S> example); // 根據實體查詢條件、查詢一批物件 <S extends T> Iterable<S> findAll(Example<S> example); // 根據實體查詢條件並排序、查詢一批物件 <S extends T> Iterable<S> findAll(Example<S> example, Sort sort); // 根據實體查詢條件並分頁,查詢一批物件 <S extends T> Page<S> findAll(Example<S> example, Pageable pageable); // 根據實體查詢條件、查詢符合條件的物件個數 <S extends T> long count(Example<S> example); // 根據實體查詢條件、判斷是否有符合條件的物件 <S extends T> boolean exists(Example<S> example); // 根據實體查詢條件、判斷是否有符合條件的物件 <S extends T, R> R findBy(Example<S> example, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction); }
第一步 :建立User實體和UserAddress實體
// User表 @Data @Entity @NoArgsConstructor @AllArgsConstructor @Builder @ToString(exclude = "address") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; private String email; private Integer age; private LocalDateTime createTime; private LocalDateTime updateTime; @OneToMany(mappedBy = "user",fetch = FetchType.LAZY) private List<UserAddress> address; } // Address表 @Entity @Data @Builder @AllArgsConstructor @NoArgsConstructor @ToString(exclude = "user") public class UserAddress { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String address; @ManyToOne(cascade = CascadeType.ALL) private User user; }
第二步: 編寫DAO層,JpaRepository已經繼承QueryByExampleExceutor
public interface UserAddressRepo extends JpaRepository<UserAddress,Integer> { }
第三步:測試
@Test public void test01 () { User user = User.builder() .name("jack") .email("123456@126.com") .age(20) .build(); userAddressRepo.saveAll(Lists.newArrayList(UserAddress.builder() .address("shanghai").user(user).build(),UserAddress.builder() .address("beijing").user(user).build())); } @Test public void testQBEE() throws JsonProcessingException { User user = User.builder() .name("jack") .age(20) .email("12345") .build(); UserAddress userAddress = UserAddress.builder() .address("shanghai") .user(user) .build(); ObjectMapper objectMapper = new ObjectMapper(); // 建立匹配器,構建動態查詢條件 ExampleMatcher exampleMatcher = ExampleMatcher.matching() .withMatcher("user.email",ExampleMatcher.GenericPropertyMatchers.startsWith()) .withMatcher("address",ExampleMatcher.GenericPropertyMatchers.startsWith()); Page<UserAddress> u = userAddressRepo.findAll(Example.of(userAddress,exampleMatcher), PageRequest.of(0,2)); System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(u)); }
一開始寫這個程式碼的時候,我也比較懵逼, Example是什麼?ExampleMatcher是什麼? 下面我一一介紹。
首先:我們先看Example的原始碼
public interface Example<T> { static <T> Example<T> of(T probe) { return new TypedExample<>(probe, ExampleMatcher.matching()); } static <T> Example<T> of(T probe, ExampleMatcher matcher) { return new TypedExample<>(probe, matcher); } T getProbe(); ExampleMatcher getMatcher(); @SuppressWarnings("unchecked") default Class<T> getProbeType() { return (Class<T>) ProxyUtils.getUserClass(getProbe().getClass()); } }
建立Example的兩個方法 :
上圖是ExampleMatcher向外暴露的方法,我們只要關心返回值為ExampleMatcher型別的方法。
其中有三個方法我們需要注意一下:
static ExampleMatcher matching() { return matchingAll(); } static ExampleMatcher matchingAll() { return new TypedExampleMatcher().withMode(MatchMode.ALL); }
上述的這兩種方法表達的意思是一樣的。兩者採用的都是MatcheMode.ALL的模式,即AND模式,生成的SQL如下:
Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where (useraddres0_.address like ? escape ?) and user1_.name=? and (user1_.email like ? escape ?) and user1_.age=20
可以看到,這些查詢條件都是AND的關係。再看另外一種方法
static ExampleMatcher matchingAny() { return new TypedExampleMatcher().withMode(MatchMode.ANY); }
當前方法與上面兩個方法不一樣的地方在於:第三個MatchMode.Any,表示查詢條件是or的關係
Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where useraddres0_.address like ? escape ? or user1_.name=? or user1_.email like ? escape ? or user1_.age=20
以上就是初始化ExampleMatcher範例的方法,你在運用中需要注意and 和 or的關係
// 哪些屬性的paths忽略大小寫,可以指定多個引數 ExampleMatcher withIgnoreCase(String... propertyPaths); // 提供一個預設的實現方法,忽略大小寫 default ExampleMatcher withIgnoreCase() { return withIgnoreCase(true); } // 預設忽略大小寫的方式,預設false ExampleMatcher withIgnoreCase(boolean defaultIgnoreCase);
暴露的Null值處理方式如下所示:
ExampleMatcher withNullHandler(NullHandler nullHandler);
NullHandler列舉值如下所示:INCLUDE(包括)、IGNORE(忽略),
enum NullHandler { INCLUDE, IGNORE }
需要注意的是: 標識作為條件的實體物件中,一個屬性值(條件值)為NULL時,是否參與過濾;
當該選項值是INCLUDE時,標識仍參與過濾,會匹配資料庫表中該欄位值是NULL的記錄;
若為IGNORE值,表示不參與過濾;
// 把(實體類中)NULL屬性值作為查詢條件 default ExampleMatcher withIncludeNullValues() { return withNullHandler(NullHandler.INCLUDE); } // 提供一個預設實現方法,忽略(實體類中)NULL屬性 default ExampleMatcher withIgnoreNullValues() { return withNullHandler(NullHandler.IGNORE); }
我們來看一下,把(實體類中)NULL屬性值作為查詢條件使用,執行的SQL如下所示:
Hibernate: select count(useraddres0_.id) as col_0_0_ from user_address useraddres0_ inner join user user1_ on useraddres0_.user_id=user1_.id where useraddres0_.id is null or useraddres0_.address like ? escape ? or user1_.name=? or user1_.email like ? escape ? or user1_.id is null or user1_.age=20
// 忽略某些屬性(可以是多個),不參與查詢過濾條件 ExampleMatcher withIgnorePaths(String... ignoredPaths);
ExampleMatcher withStringMatcher(StringMatcher defaultStringMatcher);
預設字串的匹配方式有以下幾種 ,如下所示:
enum StringMatcher { DEFAULT, EXACT, STARTING, ENDING, CONTAINING, REGEX; }
DEFAULT:預設,作用和EXACT一樣
EXACT:相等
STARTING:開始匹配
ENDING:結束匹配
CONTAINING:包含、模糊匹配
REGEX:正規表示式
使用方法如下
withStringMatcher(ExampleMatcher.StringMatcher.ENDING)
或指定某些字串屬性匹配規則
ExampleMatcher withMatcher(String propertyPath, GenericPropertyMatcher genericPropertyMatcher);
就從上面介紹的方法,我們手動練習一下。
新建一張Dog表
@Data @Entity @AllArgsConstructor @NoArgsConstructor @Table(name = "tb_dog") public class Dog { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(columnDefinition = "int(11) NOT NULL COMMENT '主鍵' ") private Integer id; @Column(columnDefinition = "varchar(30) DEFAULT '' COMMENT '寵物名'") private String name; @Column(columnDefinition = "int(11) DEFAULT NULL COMMENT '年齡'") private Integer age; }
解釋:根據當前dog物件的屬性值作為查詢條件去查詢
@Test public void testBy01(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .build(); // AND 查詢 ExampleMatcher matcher = ExampleMatcher.matching(); //ExampleMatcher.matchingAll() 也可以 System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
Hibernate: select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_ from tb_dog dog0_ where dog0_.name=? and dog0_.age=2
解釋:根據當前dog物件的屬性值作為查詢條件去查詢
@Test public void testBy02(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .build(); // OR 查詢 ExampleMatcher matcher = ExampleMatcher.matchingAny(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_ from tb_dog dog0_ where dog0_.name=? or dog0_.age=2
解釋:指定"name"屬性忽略大小寫
@Test public void testBy03(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreCase("name"); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_ from tb_dog dog0_ where lower(dog0_.name)=? and dog0_.age=2
在Dog表中新增type欄位
@Column(columnDefinition = "varchar(20) DEFAULT NULL COMMENT '種類'") private String type;
解釋:不指定屬性,預設為所有查詢字串條件加上忽略大小寫條件
@Test public void testBy04(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreCase(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where lower(dog0_.name)=? and lower(dog0_.type)=? and dog0_.age=2
解釋:把(實體類中)NULL屬性值作為查詢條件使用
@Test public void testBy05(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreCase() .withIncludeNullValues(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where lower(dog0_.type)=? and (dog0_.id is null) and dog0_.age=2 and lower(dog0_.name)=?
解釋:把(實體類中)NULL屬性值忽略
@Test public void testBy06(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnoreNullValues(); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.name=? and dog0_.type=? and dog0_.age=2
解釋:把(實體類中)某些屬性忽略掉,不做篩選
@Test public void testBy07(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); // 忽略掉"name" 和 "type"兩個屬性 ExampleMatcher matcher = ExampleMatcher.matching() .withIgnorePaths("name","type"); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.age=2
解釋:把(實體類中)所有字串屬性匹配規則設定為 EXACT (相等)
@Test public void testBy08(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() // 字串屬性提供的匹配規則 EXACT相等 .withStringMatcher( ExampleMatcher.StringMatcher.EXACT); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.name=? and dog0_.age=2 and dog0_.type=?
解釋:把(實體類中)所有字串屬性匹配規則設定為 STARTING/ENDING (模糊查詢)
public void testBy09(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() // 設定為開始匹配 .withStringMatcher(ExampleMatcher.StringMatcher.STARTING); // 設定為結束匹配 //.withStringMatcher(ExampleMatcher.StringMatcher.ENDING); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.age=2 and (dog0_.type like ? escape ?) and (dog0_.name like ? escape ?)
解釋:把(實體類中)所有字串屬性匹配規則設定為 Containing (包含模糊查詢)
@Test public void testBy11(){ Dog dog = Dog.builder() .name("TIMI") .age(2) .type("L") .build(); ExampleMatcher matcher = ExampleMatcher.matching() // 包含模糊查詢 .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING); System.out.println(dogRepo.findAll(Example.of(dog, matcher))); }
執行SQL結果如下所示:
select dog0_.id as id1_3_, dog0_.age as age2_3_, dog0_.name as name3_3_, dog0_.type as type4_3_ from tb_dog dog0_ where dog0_.age=2 and (dog0_.type like ? escape ?) and (dog0_.name like ? escape ?)
以上就是Spring Data JPA系列QueryByExampleExecutor使用詳解的詳細內容,更多關於Spring Data JPA QueryByExampleExecutor的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45