Spring JPA自定义查询结果的接收方式

 更新时间:2024年01月20日 10:06:27   作者:晓风残月淡  
这篇文章主要介绍了Spring JPA自定义查询结果的接收方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一、标准使用方法

//构建实体类
@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private Integer age;
    private String address;
}
//继承JPA
public interface UserRepository extends JpaRepository<User,Long> {
}
//调用测试
@RunWith(SpringRunner.class)
@SpringBootTest
class UserTest {
    @Autowired
    UserRepository userRepository;
    @Test
    void testUser() {
        User newUser = User.builder()
				        .id(1L)
				        .username("zhangsan")
				        .age(18)
				        .address("北京市").build();
        User savedUser = userRepository.save(newUser);
        assertEquals("zhangsan",savedUser.getUsername());
    }
}

如图所示,插入成功。

二、自定义查询结果的接收

假设我们不想查询user表中的所有字段,而只需要其中的几个字段作为前端输出。

当然,JPA给我们提供了自定义SQL的功能进行个性化的查询。使用@Query就可以自定义SQL语句,编写自定义的查询语句了。

但是,它的使用方式分为两种:

  • 一种是特定JPQL语言,这是通过实体对象来查询属性,而不用考虑对应的表名称和字段名称。
  • 一种是SQL语言,还是像原来一样操作对应的表和字段。

1.那么在UserRepository 中应该怎么写自定义查询语句呢?

//创建个性化的DTO用于接收
@Value
public class UserDTO {
    Long id;
    String username;
}
//写sql语句
public interface UserRepository extends JpaRepository<User,Long> {
    //@Query("select u from User u where u.id =?1")
    //是像这样,还是怎么写呢?
    UserDTO findUserDTOByID(Long id);
}
//调用
@RunWith(SpringRunner.class)
@SpringBootTest
class UserTest {
    @Autowired
    UserRepository userRepository;

    @Test
    void testUserDTO() {
        UserDTO dto = userRepository.findUserDTOByID(1L);
        assertEquals("zhangsan",dto.getUsername());
        
    }
}

可能的错误的查询方式:

//1.意图User实体自动映射某些属性到UserDTO
public interface UserRepository extends JpaRepository<User,Long> {
    @Query("select u from User u where u.id =?1")
    UserDTO findUserDTOByID(Long id);
    //但是会报org.springframework.core.convert.ConverterNotFoundException错误
}
//2.意图挑出User的某些字段会自动映射到UserDTO
public interface UserRepository extends JpaRepository<User,Long> {
    @Query("select u.id,u.username from User u where u.id =?1")
    UserDTO findUserDTOByID(Long id);
    //但是会报org.springframework.core.convert.ConverterNotFoundException错误
}
//3.意图挑出User的某些字段会自动映射到UserDTO
public interface UserDTORepository extends JpaRepository<UserDTO,Long> {
    @Query("select u.id,u.username from User u where u.id =?1")
    UserDTO findByID(Long id);
    //但是这会生成一个新表
}

在上面虽然UserDTO只是User中的子集,只有它的两个属性,但是如果直接用UserDTO接收查询结构,就会报这种 类型转换错误

这是因为UserRepository是实体对象User的仓库,必须用User来接收,不能用别的对象来接收。

那么我们能不能再创建一个UserDTORepository来接收查询结果呢?

这是不行的,因为UserDTORepository必须映射对应的表,才能查询UserDTO对象。而我们当然不希望又创建与User相似的表。

正确的查询方式:

//1.使用Object接收
public interface UserRepository extends JpaRepository<User,Long> {
    @Query("select u.id,u.username from User u where u.id =?1")
    Object findUserDTOByID(Long id);
    //倒是能接收到结果,但是丢失了属性名称,必须数组的索引访问,不方便
}
//2.使用全限定名接收
public interface UserRepository extends JpaRepository<User,Long> {
    @Query("select new com.example.admin.ums.domain.user.UserDTO(id,username) from User u where u.id =?1")
    UserDTO findUserDTOByID(Long id);
    //能接收到结果,但是UserDTO必须有构造函数,带上所有参数,也不方便
}
//3.定义接口来接收,使用的是projections接口投影机制
public interface IUser {
	//定义这些getter方法才能接收结果
    Long getId();
    String getUsername();
}
//用接口接收查询结果
public interface UserRepository extends JpaRepository<User,Long> {
    @Query("select u.id as id ,u.username as username  from User u where u.id =?1")
    IUser findUserDTOByID(Long id);
    //能查询到结果,但是必须用接口接收,可能不习惯
}
//4.泛型动态查询投影
public interface UserRepository extends JpaRepository<User,Long> {
    <T> T  findById(Long id, Class<T> type);
    //只需要输入ID和类类型就能查到结果,这个利用了方法名的查询生成器机制,不用专门写@Query
    //同时使用动态查询投影,所以不用输入很多参数,方便了很多,强烈推荐
}
//5.用Map接收查询的结果
public interface UserRepository extends JpaRepository<User,Long> {
    @Query("select u.id as id ,u.username as username, u.address as address  from User u where u.id =?1")
    Map<String,Object> findUserDTO(Long id);
    //需要写JPQL语句,必须用as取别名,否则就没有key值
    //优点是不用构造DTO直接输出给前端
    //缺点是查出来的不是对象,不方便再处理业务逻辑,若参数很多,就会很繁琐    
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • springboot线程池监控的简单实现

    springboot线程池监控的简单实现

    本文主要介绍了springboot线程池监控的简单实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Java中的interrupt、interrupted和isInterrupted方法区别详解

    Java中的interrupt、interrupted和isInterrupted方法区别详解

    这篇文章主要介绍了Java中的interrupt、interrupted和isInterrupted方法区别详解,interrupt用于中断线程,调用该方法的线程的状态将会被设置为中断状态,线程中断仅仅是设置线程的中断状态位,并不会停止线程,需要用户自己去监视线程的状态并作出处理,需要的朋友可以参考下
    2023-12-12
  • MybatisPlus实现逻辑删除功能

    MybatisPlus实现逻辑删除功能

    这篇文章主要介绍了MybatisPlus实现逻辑删除功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • SpringBoot 启动流程追踪方法分享

    SpringBoot 启动流程追踪方法分享

    这篇文章主要介绍了SpringBoot 启动流程追踪方法分享的相关资料,需要的朋友可以参考下
    2023-08-08
  • SpringBoot Redisson 集成的实现示例

    SpringBoot Redisson 集成的实现示例

    本文主要介绍了SpringBoot Redisson 集成的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-05-05
  • java 题解LeetCode38外观数列示例

    java 题解LeetCode38外观数列示例

    这篇文章主要为大家介绍了java 题解LeetCode38外观数列示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Java HttpClient技术详解

    Java HttpClient技术详解

    Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用和灵活性(具体区别,日后我们再讨论),它不仅是客户端发送Http请求变得容易,而且也方便了开发人员测试接口(基于Http协议的),即提高了开发的效率,也方便提高代码的健壮性
    2021-10-10
  • 基于java实现斗地主代码实例解析

    基于java实现斗地主代码实例解析

    这篇文章主要介绍了基于java实现斗地主代码实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • Java实现预览与打印功能详解

    Java实现预览与打印功能详解

    在 Java 中,打印功能主要依赖 java.awt.print 包,该包提供了与打印相关的一些关键类,比如 PrinterJob 和 PageFormat,它们构成了 Java 打印框架的核心,接下来我们将一步步实现一个简单的预览和打印功能,需要的朋友可以参考下
    2025-07-07
  • java8实现List中对象属性的去重方法

    java8实现List中对象属性的去重方法

    这篇文章主要介绍了java8实现List中对象属性的去重方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03

最新评论