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

Spring Boot使用EntityManager创建动态查询时count(*)报错如何解决

现有代码问题排查
  • 依赖注入逻辑错误:你写的entityManager = entityManager属于自我赋值,实际没有把注入的em赋值给全局变量,会导致后续调用entityManager!!直接抛出空指针异常,正确的赋值应该是entityManager = em
  • 查询仅创建未执行:createQuery方法仅构造了查询对象,没有调用getResultList()执行查询获取结果,自然拿不到统计数据
  • 变量命名笔误:你定义的teamDate从业务逻辑来看应该是teamData,虽然不影响运行但容易造成后续维护混淆
该查询方式的合理性判断

固定统计逻辑的场景下,直接通过EntityManager.createQuery写JPQL做count统计是合理的,性能和可读性都符合要求。如果你的统计逻辑需要动态拼接筛选条件、动态切换分组字段、动态调整统计项,硬编码JPQL的方式就不合理,容易出现SQL注入风险,且维护成本极高,这种场景推荐使用JPA Criteria API构造动态查询。

正确实现示例

1. 固定统计逻辑的修复版代码

// 先修正依赖注入赋值
@Autowired
fun JobCompletionNotificationListener(em: EntityManager) {
    entityManager = em
}

override fun afterJob(jobExecution: JobExecution) {
    if (jobExecution.status === BatchStatus.COMPLETED){
        log.info("!!! JOB FINISHED! Time to verify the results")
        val teamData : MutableMap<String, Long> = HashMap()
        // 执行查询并遍历结果
        val resultList = entityManager!!.createQuery(
            "SELECT m.team1 , COUNT(*) FROM Match m GROUP BY m.team1",
            Array<Any>::class.java
        ).resultList
        resultList.forEach { row ->
            val teamName = row[0] as String
            val count = row[1] as Long
            teamData[teamName] = count
        }
        // 后续可自行处理teamData的业务逻辑
    }
}

注意COUNT(*)返回的是Long类型,不要强行转为Int避免数值溢出。

2. 动态count查询(Criteria API实现)

如果需要动态加筛选条件,比如可选按比赛日期过滤再统计,示例代码如下:

override fun afterJob(jobExecution: JobExecution) {
    if (jobExecution.status === BatchStatus.COMPLETED){
        val cb = entityManager!!.criteriaBuilder
        val query = cb.createQuery(Array<Any>::class.java)
        val root = query.from(Match::class.java)

        // 动态构造查询条件示例:如果有传入开始日期就加过滤
        val predicates = mutableListOf<Predicate>()
        if (startDate != null) {
            predicates.add(cb.greaterThanOrEqualTo(root.get("matchDate"), startDate))
        }
        query.where(*predicates.toTypedArray())

        // 构造统计+分组逻辑
        query.multiselect(
            root.get<String>("team1"),
            cb.count(root) // 等价于COUNT(*)
        )
        query.groupBy(root.get<String>("team1"))

        // 执行查询
        val resultList = entityManager!!.createQuery(query).resultList
        // 后续处理结果逻辑和上面一致
    }
}

这种方式完全避免了字符串拼接的风险,类型安全,适合复杂动态统计场景使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 17:45:04