Spring Boot的@Query注解
摘要
- 聊聊Spring Boot的@Query注解
- 参考:Spring Boot自定义JpaRepository基类
@Query说明
1 |
|
基本用法示例
-
@Entity
1 |
|
-
Dto
1 |
|
-
Jpa
1 | public interface CountryJpaRepository extends BaseJpaRepository<Country, Long> { |
说明
-
返回@Entity对象,查询全部属性时,sql和hql都支持直接转换
-
返回@Entity对象,查询部分属性时,sql不支持直接转换,hql时,实体要有对应的构造方法
-
hql也可以返回Dto对象,查询部分属性时,同样需要Dto有对应的构造方法,注意Dto必须使用全路径
sql查询部分属性直接转换成对象的方法
-
方法1,前一篇文章Spring Boot自定义JpaRepository基类中通过自定义JpaRepository基类,转换@Entity对象和Dto对象都支持
-
方法2,注入自定义的结果转换器,只能转换为Dto对象,下面说明如何实现
注入自定义的结果转换器
-
无论是sql还是hql,查询部分属性时,jpa输出的结果都会被转化为Map对象,我们只需要注入一个能将Map转换为指定对象的转换器就可以了
1 | /** |
-
定义标记注解
1 | /** |
-
此时Dto对象上要加上@JpaDto注解
1 |
|
-
JpaRepository示例
1 | public interface CountryJpaRepository extends BaseJpaRepository<Country, Long> { |
说明
-
返回注解了@JpaDto注解的对象时,hql和sql都支持部分字段查询,但要注意字段要加as别名,别名与Dto对象属性名称要一致;
-
部分字段查询时,Dto对象中不必创建对应的构造方法;
-
查询部分属性时,不支持返回@Entity对象,即使在@Entity类上增加@JpaDto注解也不好使,说明其返回的不是Map对象
-
hql返回部分属性时,如果直接返回@Entity对象,会抛异常
Failed to convert from type [java.lang.Object[]] to type [com.example.demo.Country]
,提示类型转换失败,因其返回类型是java.lang.Object[],所以也说明为什么要用构造方法的形式接收返回数据,就是要与数组位置一一对应上,所以hql返回部分属性,就要使用构造方法的形式;1
2
3
4
5
6
7//错误
Country findCountryHqlByNameError(String name);
//正确
Country findCountryHqlByNameOk(String name); -
sql返回部分属性时,如果直接返回@Entity对象,会抛异常
No such column: 'code_three'.
,提示缺少字段。说明该形式在封装@Entity对象时需要遍历其所有@Column字段并为其赋值,此时可以返回Dto或者Map,也可以使用自定义JpaRepository的方式,还有一种方法就是使用命名查询,就是@NamedNativeQuery和@SqlResultSetMapping;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//错误
Country findCountrySqlByNameError(String name);
//正确,之后可以将map转换为@Entity对象,如通过json的方式
Map findCountrySqlByNameOk(String name);
//正确
Object[] findCountrySqlByNameOk2(String name);
//正确,CountryDto要加上@JpaDto注解
CountryDto findCountrySqlByNameOk3(String name);
命名查询
-
@NamedQuery,用于执行hql
1 |
|
-
@NamedNativeQuery和@SqlResultSetMapping,用于执行sql,可以指定结果类型,不指定结果类型时返回java.lang.Object[]
1 |
|
说明
-
命名查询的注解只能声明在对应的@Entity类型上
-
@NamedNativeQuery名称必须全局唯一,可以通过
entityManager.createNamedQuery(String queryName)
进行调用 -
sql查询部分字段时@Entity一定要有对应的构造方法
-
返回类型必须是@Entity对象
-
@SqlResultSetMapping可以单独使用,其功能就是将sql的查询结果转换为指定的类型,
entityManager.createNativeQuery(String sqlString, String resultSetMapping)
使用方法
-
通过entityManager的方法进行调用
1
2
3List list = entityManager.createNamedQuery("SQL_FIND_ALL_COUNTRY").getResultList();
List list = entityManager.createNativeQuery("select id,name_zh as nameZh,name_en as nameEn from tbl_country","SQL_RESULT_COUNTRY_SOME_FIELD").getResultList(); -
通过在JpaRepository声明指定的@Query方法,并指定其name属性为对应的@NamedNativeQuery的name值
1
2
3
4
5
6
7
8
9
10
11
12
13public interface CountryJpaRepository extends BaseJpaRepository<Country, Long> {
List<Country> nameHqlFindAll();
List<Country> nameSqlFindAll();
List<Country> nameSqlFindAll2();
List<Country> nameSqlFindSomeField();
}
关于在@Query注解中使用Mysql的原生sql时的一些小技巧
-
动态sql通过mysql的if语句实现
1
2
3
4
5
Country findCountrySqlByName(String name);
Country findCountrySqlByName(; String name) -
拼接like使用mysql的CONCAT语句
1
2
3
4
5",nativeQuery = true)
Country findCountrySqlByName(String name);
@Query(value = "SELECT * FROM tbl_country WHERE name like CONCAT('%',:name,'%')",nativeQuery = true)
Country findCountrySqlByName(@Param("name") String name); -
日期比较时可以直接使用
>
和<
等比较符号,参数为Date、LocalDate和LocalDateTime1
2
Long countCountryByDate(; LocalDateTime lastTime)