You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将按SignLogUUID分组取最大id的SQL改写为JPA Criteria实现

JPA 实现按SignLogUUID分组取最新记录方案

需求说明

需要实现的查询逻辑等价于以下原生SQL:

SELECT * FROM webamdb.sign_log
WHERE id IN (SELECT MAX(id) AS id
             FROM webamdb.sign_log 
             GROUP BY SignLogUUID) 
ORDER BY CreateTime;

即按SignLogUUID分组取每组最大id(即每组最新记录),查询对应全量字段后按创建时间排序。以下优先提供要求的JPA Criteria写法,同时补充简化实现方案。


1. 优先实现:JPA Criteria API 写法

该写法为JPA标准类型安全实现,支持动态条件拼接,适合复杂业务场景。需要注入EntityManager使用,代码示例如下:

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import java.util.List;

// 可写在Service层或自定义Repository实现类中
@PersistenceContext
private EntityManager entityManager;

public List<SignLog> listLatestGroupBySignLogUuid() {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    // 构建主查询:查询SignLog实体全量字段
    CriteriaQuery<SignLog> mainQuery = cb.createQuery(SignLog.class);
    Root<SignLog> mainRoot = mainQuery.from(SignLog.class);

    // 构建子查询:按signLogUUID分组,取每组最大id
    Subquery<Long> maxIdSubQuery = mainQuery.subquery(Long.class);
    Root<SignLog> subRoot = maxIdSubQuery.from(SignLog.class);
    maxIdSubQuery.select(cb.max(subRoot.get("id")))
            .groupBy(subRoot.get("signLogUUID"));

    // 组装主查询逻辑:id在子查询结果集中,按createTime升序排序(需要倒序可替换为cb.desc)
    mainQuery.select(mainRoot)
            .where(cb.in(mainRoot.get("id")).value(maxIdSubQuery))
            .orderBy(cb.asc(mainRoot.get("createTime")));

    return entityManager.createQuery(mainQuery).getResultList();
}

注:如果使用javax.persistence包(Spring Boot 2.x版本),将上述导入包路径替换为javax.persistence对应类即可。


2. 简化实现:Spring Data JPA JPQL 写法

如果查询逻辑固定、不需要动态拼接条件,可以直接在Spring Data JPA的Repository接口中通过@Query注解写JPQL,无需手动操作EntityManager,代码更简洁:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;

public interface SignLogRepository extends JpaRepository<SignLog, Long> {

    @Query("SELECT s FROM SignLog s " +
            "WHERE s.id IN (SELECT MAX(s2.id) FROM SignLog s2 GROUP BY s2.signLogUUID) " +
            "ORDER BY s.createTime ASC")
    List<SignLog> listLatestGroupBySignLogUuid();
}

注意事项

  • 所有JPA查询中引用字段时,传入的是实体类的驼峰命名字段,而非数据库下划线列名。例如实体中定义的字段是signLogUUID、createTime,不要直接传入数据库列名SignLogUUID、CreateTime,否则会抛出属性找不到的异常。
  • 你当前实体中WebInfo关联配置为FetchType.LAZY懒加载,若查询后需要访问关联的webInfo属性,请在事务上下文内操作,避免懒加载异常;如果需要查询时直接加载关联数据,JPQL可追加LEFT JOIN FETCH s.webInfo,Criteria写法可通过mainRoot.fetch("webInfo", JoinType.LEFT)实现。
  • 若必须使用原生SQL,可在@Query注解中添加nativeQuery = true参数,直接写入你提供的原生SQL即可,但该方式会牺牲数据库兼容性,非必要不推荐。

内容的提问来源于stack exchange,提问作者Jessie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:51:29