Spring Data JPA的查询方式有很多,下面用示例来挨个介绍一下。
Entity
package com.school1024.spring.boot.data.jpa.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import com.school1024.spring.boot.data.jpa.model.type.GenderType; @Entity @Table(name = "book") public class BookModel { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; @Column(length = 256, nullable = false) private String name; @Column(length = 256, nullable = false) private String author; @Enumerated(EnumType.STRING) @Column(name = "gender", length = 100, nullable = false) private GenderType gender; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public GenderType getGender() { return gender; } public void setGender(GenderType gender) { this.gender = gender; } @Override public String toString() { return "BookModel [id=" + id + ", name=" + name + ", author=" + author + ", gender=" + gender + "]"; } }
DAO
package com.school1024.spring.boot.data.jpa.dao; import java.util.List; import java.util.Map; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import com.school1024.spring.boot.data.jpa.model.BookModel; import com.school1024.spring.boot.data.jpa.model.type.GenderType; public interface BookDao extends JpaRepository<BookModel, Integer>, JpaSpecificationExecutor<BookModel> { List<BookModel> findByGender(GenderType gender); @Query("FROM BookModel WHERE gender=:gender") List<BookModel> find2(@Param("gender") GenderType gender); @Query("SELECT new Map(id as id, name as name) FROM BookModel WHERE gender=:gender") List<Map<String, Object>> find3(@Param("gender") GenderType gender); @Query(nativeQuery = true, value = "SELECT * FROM book WHERE author=:author") List<BookModel> find4(@Param("author") String author); @Query(nativeQuery = true, value = "SELECT id, concat('《',name,'》') as name, author, gender FROM book WHERE author=:author") List<Object[]> find5(@Param("author") String author); }
package com.school1024.spring.boot.data.jpa.feature; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.junit.Assert; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Example; import org.springframework.data.jpa.domain.Specification; import com.school1024.spring.boot.data.jpa.SpringBootDataJpaTest; import com.school1024.spring.boot.data.jpa.dao.BookDao; import com.school1024.spring.boot.data.jpa.model.BookModel; import com.school1024.spring.boot.data.jpa.model.type.GenderType; public class QueryTest extends SpringBootDataJpaTest { @Autowired private BookDao dao; @Test public void test() { // 通过自带的方法查询 long count = dao.count(); System.out.println(count); List<BookModel> result = dao.findAll(); for (BookModel bookModel : result) { System.out.println(bookModel); } } }
这些方法是Spring Data自带的,一些常见的简单操作都可以完成。
2 BookModel [id=1, name=张三疯自传, author=张三, gender=MALE] BookModel [id=2, name=武大烧饼烹饪技巧, author=武大, gender=MALE]
这是上面的输出内容,接下来的示例就用这2条数据。
DAO接口中定义一个方法
List<BookModel> findByGender(GenderType gender);
测试用例
@Test public void test1() { List<BookModel> result = dao.findByGender(GenderType.MALE); Assert.assertTrue(result.size() > 0); }
通过对方法的命名来完成查询,方法名里指定属性和判断方法,默认是等于,命名规则可以查看官方文档,里面很详细,一般的查询都可以实现。这种方式有几个弊端,如果条件过多,方法名会很长,有些查询条件不是必填的,不好处理。下面的方式可以解决第一个问题,条件不是必填的可以用Specification处理,后面有介绍。
注解里要写JPQL,或者原生的SQL。
@Query("FROM BookModel WHERE gender=:gender") List<BookModel> find2(@Param("gender") GenderType gender);
测试用例
@Test public void test2() { List<BookModel> rs = dao.find2(GenderType.MALE); Assert.assertTrue(rs.size() > 0); }
有时候你想写个复杂的查询,返回结果并不是Entity,这时候你还可以定义个Map
@Query("SELECT new Map(id as id, name as name) FROM BookModel WHERE gender=:gender") List<Map<String, Object>> find3(@Param("gender") GenderType gender);
示例
@Test public void test3() { List<Map<String, Object>> rs = dao.find3(GenderType.MALE); for (Map<String, Object> map : rs) { System.out.println(map); } }
如果JPQL解决不了,你一定要写原生SQL也可以,但这种方式不推荐。需要设置nativeQuery=true。
@Query(nativeQuery = true, value = "SELECT * FROM book WHERE author=:author") List<BookModel> find4(@Param("author") String author);
示例
@Test public void test4() { List<BookModel> rs = dao.find4("张三"); for (BookModel bookModel : rs) { System.out.println(bookModel); } }
上面是比较好的情况,返回值可以映射到一个Entity上,如果返回值是一个自定义的列,根本匹配不了,可以通过下面的方式
@Query(nativeQuery = true, value = "SELECT id, concat('《',name,'》') as name, author, gender FROM book WHERE author=:author") List<Object[]> find5(@Param("author") String author);
示例
@Test public void test6() { List<Object[]> rs = dao.find5("张三"); for (Object[] objects : rs) { for (Object object : objects) { System.out.println(object); } } }
如果你的查询条件比较多,而且又都是选填的,那可以用Specification查询
示例
@Test public void test7() { List<BookModel> rs = dao.findAll(new Specification<BookModel>() { @Override public Predicate toPredicate(Root<BookModel> root, CriteriaQuery<?> query, CriteriaBuilder cb) { List<Predicate> list = new ArrayList<Predicate>(); list.add(cb.like(root.get("name").as(String.class), "张" + "%")); list.add(cb.equal(root.get("gender").as(GenderType.class), GenderType.MALE)); Predicate[] p = new Predicate[list.size()]; return cb.and(list.toArray(p)); } }); for (BookModel bookModel : rs) { System.out.println(bookModel); } }
Specification是最后的杀手锏,这里能完成所有的查询操作。
很久以前用Hibernate的时候,用过Example查询,这对于一些简单的根据某些属性查询来说,真的特别方便,Spring Data同样支持。
通过Example查询
@Test public void test8() { // 通过Example查询 BookModel model = new BookModel(); model.setAuthor("张三"); List<BookModel> rs = dao.findAll(Example.of(model)); for (BookModel bookModel : rs) { System.out.println(bookModel); } }
你可以设置实体的多个属性,这些都会被添加到where里。
除了以上,还可以通过QueryDSL查询,这个后面单独介绍。
以上所有代码都在GitHub中:https://github.com/ckwen/school1024-java/tree/master/spring-boot/spring-boot-data-jpa