Spring Data JPA 自定义查询

spring data jpa 提供了方便快捷的查询数据库方式,只要按照它的约定,编写接口和函数定义,即可很方便的从数据库中查询到想用的数据。

https://docs.spring.io/spring-data/jpa/docs/1.11.13.RELEASE/reference/html/#jpa.repositories

但是每个应用业务逻辑的复杂度不同,有时候是必须要自己定义JPQL甚至native sql 来做自己的查询,本文介绍如何创建自定义的查询。

1. 自定义一个接口,该接口用来声明自己额外定义的查询。

public interface CustomizedLogRepository {
    
    public List<LogDTO> searchLogs(String appId, String keyword);
    
    public long searchLogCount(String appId, String keyword);
}

2. 创建一个接口,该接口 extends JpaRepository 或者 CurdRepository, 以及上面自己定义的接口 CustomizedLogRepository

public interface LogRepository extends CrudRepository<LogDTO, Integer>, CustomizedLogRepository {

}

3. 实现LogRepository
注意此处的类名,必须以 2 中创建的接口的名字LogRepository ,后面加上 Impl 来声明,而不是写成 CustomizedLogRepositoryImpl

public class LogRepositoryImpl implements CustomizedLogRepository {
    
    @Autowired
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<Ankonlog> searchLogs(String appId, String keyword) {
        ......
    }

    @Override
    public long searchLogCount(String appId, String keyword) {
        ......
    }
}

至此,自定义JPQL查询完成。

native query

native query 可以用原始的 sql 而不是 jpql 来查询数据库,更加的灵活。
但是Spring Data JPA 对于 native query 分页、排序的处理并不支持,但是可以通过如下方法解决:

@Query(value = "SELECT DISTINCT device_sn FROM motion_record WHERE device_sn LIKE %:deviceSn% \n#pageable\n",
            countQuery = "SELECT COUNT(DISTINCT device_sn) FROM motion_record WHERE device_sn LIKE %:deviceSn%",
            nativeQuery = true)
public Page<String> searchDevices(@Param("deviceSn") String deviceSn, Pageable pageable);

本例中结合了Page进行分页,需要特别注意的地方有两个点

  1. 必须使用 \n#pageable\n 来注入分页参数
  2. 参数的传递必须用 @Param ,试过使用 ?1 的占位符,但是运行始终报错(Spring Data JPA 1.11.13 版本)

自定义查询结果对象

有时候我们会联表查询多个表的数据,组合成我们需要的查询结果(比如 LEFT JOIN),此时我们需要另外单独定一个实体类来做返回值的映射,比如以下JPQL:

SELECT t1.id, t2.name FROM table1 t1 LEFT JOIN table2 t2 on t1.id = t2.id;

返回值是从不同的表中取出的部分字段组合而成的,那么我们可以定一个实体类:

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class ResultEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    private Integer id;
    private String name;
	public ResultEntity(Integer id, String name) {
		this.id = id;
		this.name = name;
    }
	// 所有属性的 getter/setter
	.....
}

此处实体类的定义有几个关键点

  1. 一定要用 @Entity 注解
  2. 一定要有一个主键属性,用 @Id 注解
  3. 一定要有包含全部参数的构造函数

然后,JPQL 需要改写成

SELECT new ResultEntity(t1.id, t2.name) FROM table1 t1 LEFT JOIN table2 t2 on t1.id = t2.id;

如果出现报错找不到实体类,可以在 ResultEntity 前面加上完整的包路径

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Data JPA 中,我们可以通过定义 Repository 接口中的方法,使用方法名来自动生成查询语句。但是有时候,我们需要自定义查询结果,比如说只需要查询结果中的部分字段,或者对查询结果进行聚合操作等。这时,我们可以使用 Spring Data JPA 提供的投影(Projection)功能来自定义查询结果。 投影是指将实体类中的一部分属性或关联属性映射成一个接口或类,从而返回一个自定义的结果集。Spring Data JPA 支持三种投影方式: 1. 接口投影:定义一个接口,接口中声明需要的属性,Spring Data JPA 将根据接口定义的属性生成查询结果。 2. 类投影:定义一个类,类中声明需要的属性,Spring Data JPA 将根据类定义的属性生成查询结果。 3. 动态投影:可以根据查询条件动态地返回不同的投影结果,比如说根据用户的角色返回不同的查询结果。 下面是一个简单的例子,演示如何使用接口投影来自定义查询结果: 定义一个接口投影: ```java public interface UserProjection { String getUsername(); String getEmail(); } ``` 在 UserRepository 中使用接口投影: ```java public interface UserRepository extends JpaRepository<User, Long> { List<UserProjection> findByUsername(String username); } ``` 通过上面的代码,我们可以在 UserRepository 中定义一个方法 findByUsername,该方法会返回一个 List<UserProjection> 类型的结果集,该结果集中只包含 username 和 email 两个字段。 当我们调用 findByUsername 方法时,Spring Data JPA 将根据方法名自动生成查询语句,并根据 UserProjection 接口中定义的属性生成查询结果。 当然,除了接口投影,还有其他的投影方式,你可以根据自己的需求选择适合的方式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值