本篇文章小编给大家分享一下spring-data-jpa中jpql的投影查询代码示例,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。
投影查询,就是仅仅检索表的部分字段。而不是粗暴的SELECT * FROM...检索出所有列数据。例如检索用户余额信息的时候,就不需要检索用户的头像,创建日期等字段。节省了带宽传输和内存占用,也避免了可能暴露更多数据给客户端。
这里先啰嗦一下jpql的一些注意点
操作的是对象 @Entity, 不是表, 操作的是对象属性, 也不是表字段
默认Entity名称就是类名称大写, 也可以通过修改 @Entity 属性的注解来修改
不支持使用 `` 符号, 不支持在末尾添加分号: ;
支持使用 AS 关键字起别名
准备一个演示用的实体类
import javax.persistence.*; import java.io.Serializable; import java.time.LocalDateTime; /** * 用户 */ @Entity @Table(name = "user", indexes = { @Index(columnList = "account", unique = true), }) @org.hibernate.annotations.Table(appliesTo = "user", comment = "用户") public class User implements Serializable { /** * */ private static final long serialVersionUID = -129586628554861093L; @Id @Column(columnDefinition = "INT(11) UNSIGNED COMMENT 'id'") @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; // 登录账户 @Column(columnDefinition = "VARCHAR(20) COMMENT '登录账户'", nullable = false) private String account; // 昵称 @Column(columnDefinition = "VARCHAR(20) COMMENT '昵称'") private String name; // 头像 @Column(columnDefinition = "VARCHAR(255) COMMENT '头像'") private String avatar; // 创建时间 @Column(name = "created_date", columnDefinition = "timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'", nullable = false) private LocalDateTime createdDate; // 最后修改时间 @Column(name = "last_modified_date", columnDefinition = "timestamp NULL DEFAULT NULL COMMENT '最后一次修改时间'") private LocalDateTime lastModifiedDate; // 记录状态 @Column(columnDefinition = "TINYINT(1) unsigned COMMENT '是否启用'", nullable = false) private Boolean enabled; }
检索单行单列数据
单行单列数据,比较简单了。返回的列数据类型是什么,Repository接口中检索方法的返回值就定义什么即可。
根据用户ID检索 账户字段
public interface UserRepository extends JpaRepository, JpaSpecificationExecutor { /** * 根据用户ID,检索账户信息 * @param id * @return */ @Query("SELECT u.account FROM User AS u WHERE u.id = :id") String accountById(@Param("id") Integer id); }
测试代码
@Autowired private UserRepository userRepository; @Test @Transactional(readOnly = true) public void test () { String account = userRepository.accountById(1); LOGGER.info("account={}", account); }
执行日志
在日志中可以看到执行的SQL符合要求,仅仅检索了一个列,并且返回了正确的结果。
Hibernate: select user0_.account as col_0_0_ from user user0_ where user0_.id=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1] i.s.jpa.test.JpaApplicationTest : account=KevinBlandy
检索单行多列数据
使用自定义对象 的构造器封装结果集
自定义一个封装结果集的对象
这里直接继承了User类,并且需要通过构造函数来定义需要投影检索的列
import java.time.LocalDateTime; public class UserDTO extends User { /** * */ private static final long serialVersionUID = 6393508321723484097L; public UserDTO(String account, String name, LocalDateTime createdDate) { super.setAccount(account); super.setName(name); super.setCreatedDate(createdDate); } }
根据检索出用户的基本信息:账户,昵称,创建时间,封装结果集为UserDTO对象
使用jpql中的NEW关键字指定自定义对象的全路径,并且在构造函数中指定要检索的列,既有sql的语法,又有面向对象的思想。
/** * 根据检索出用户的基本信息:账户,昵称,创建时间,封装结果集为UserDTO对象 * @param id * @return */ @Query("SELECT NEW io.springboot.jpa.entity.UserDTO(u.account, u.name, u.createdDate) FROM User AS u WHERE u.id = :id") UserDTO querySimpleInfoById(@Param("id") Integer id);
测试
@Autowired private UserRepository userRepository; @Test @Transactional(readOnly = true) public void test () { UserDTO userDTO = userRepository.querySimpleInfoById(1); LOGGER.info("user={}", userDTO); }
执行日志
Hibernate: select user0_.account as col_0_0_, user0_.name as col_1_0_, user0_.created_date as col_2_0_ from user user0_ where user0_.id=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1] i.s.jpa.test.JpaApplicationTest : user=User [id=null, account=KevinBlandy, name=Vin, avatar=null, createdDate=2020-07-16T10:39:02, lastModifiedDate=null, enabled=null]
使用 Oject[] 封装结果集
把结果集封装为数组集合,并不需要重新定义对象,但是缺点就是需要自己记住每个数组下标下的数据代表的是什么 。
根据检索出用户的基本信息:账户,昵称,创建时间,封装结果集为Object数组
/** * 根据检索出用户的基本信息:账户,昵称,创建时间,封装结果集为“Object[]” * @param id * @return */ @Query("SELECT u.account, u.name, u.createdDate FROM User AS u WHERE u.id = :id") Object querySimpleInfoById(@Param("id") Integer id);
注意,这里的返回值定义的是Object,而不是想象中的Object[],返回值定义为Object[],jpa就会把结果集封装为一个二维数组,适合多行多列的情况。
这里演示的是根据id检索,只可能是单行,多列。所以定义成Object,自己强转换一下就好了。
测试
@Autowired private UserRepository userRepository; @Test @Transactional(readOnly = true) public void test () { // 强制转换为Object[] Object[] results = (Object[]) userRepository.querySimpleInfoById(1); for (Object result : results) { LOGGER.info("result={}", result); // 遍历数组的所偶结果 } }
执行日志
Hibernate: select user0_.account as col_0_0_, user0_.name as col_1_0_, user0_.created_date as col_2_0_ from user user0_ where user0_.id=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1] i.s.jpa.test.JpaApplicationTest : result=KevinBlandy i.s.jpa.test.JpaApplicationTest : result=Vin i.s.jpa.test.JpaApplicationTest : result=2020-07-16T10:39:02
使用 Map
使用map作为结果集的好处就是,不需要重新定义对象。而且可以根据key找到自己要的字段。我觉得最方便的一种 方法了,借助于spring的,BeanUtils,可以把Map转换为对象。
根据检索出用户的基本信息:账户,昵称,创建时间,封装结果集为“Map
/** * 根据检索出用户的基本信息:账户,昵称,创建时间,封装结果集为“Map” * @param id * @return */ @Query("SELECT NEW MAP(u.account AS account, u.name AS name, u.createdDate AS createdDate) FROM User AS u WHERE u.id = :id") Map querySimpleInfoById(@Param("id") Integer id);
需要对检索的列, 使用AS起别名, 作为key的名称,如果不使用AS别名的话,单行单列的情况下,key = null, 多行的情况下, key = 序号(从0开始)
{ "0":"Vin", "1":“KevinBlandy” }
测试代码
@Autowired private UserRepository userRepository; @Test @Transactional(readOnly = true) public void test () { Mapresult = userRepository.querySimpleInfoById(1); LOGGER.info("result={}", result); }
执行日志
Hibernate: select user0_.account as col_0_0_, user0_.name as col_1_0_, user0_.created_date as col_2_0_ from user user0_ where user0_.id=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1] i.s.jpa.test.JpaApplicationTest : result={name=Vin, account=KevinBlandy, createdDate=2020-07-16T10:39:02}
检索多列N行
对于有多行的记录封装,就很简单了。在上面的基础上,把返回值结果修改为数组或者Collection子类即可。
单行多列 List
多行多列 List
多行队列 List
多行队列 List
多行队列 Object[],每一个Object元素都是一个数组
...
忍者必须死34399账号登录版 最新版v1.0.138v2.0.72
下载勇者秘境oppo版 安卓版v1.0.5
下载忍者必须死3一加版 最新版v1.0.138v2.0.72
下载绝世仙王官方正版 最新安卓版v1.0.49
下载Goat Simulator 3手机版 安卓版v1.0.8.2
Goat Simulator 3手机版是一个非常有趣的模拟游
Goat Simulator 3国际服 安卓版v1.0.8.2
Goat Simulator 3国际版是一个非常有趣的山羊模
烟花燃放模拟器中文版 2025最新版v1.0
烟花燃放模拟器是款仿真的烟花绽放模拟器类型单机小游戏,全方位
我的世界动漫世界 手机版v友y整合
我的世界动漫世界模组整合包是一款加入了动漫元素的素材整合包,
我的世界贝爷生存整合包 最新版v隔壁老王
我的世界MITE贝爷生存整合包是一款根据原版MC制作的魔改整