【问题标题】:Bug in Spring Data JPA: Spring Data returns List<BigInteger> instead of List<Long>Spring Data JPA 中的错误:Spring Data 返回 List<BigInteger> 而不是 List<Long>
【发布时间】:2026-02-01 01:05:03
【问题描述】:

我在 spring-data 上实现了 DAO:

public interface TestDataRepository extends CrudRepository<DpConfigData, Long> {
@Query(value = "select distinct(oid) from unit", nativeQuery = true)
    List<Long> testMethod();
}

和单元测试来测试提到的 DAO:

@Test
public void test(){
    List<Long> testData = dpConfigDataEntityDataRepository.testMethod();
    for (Long oid:testData){
        System.out.print(oid);
    }
}

运行测试给出奇怪的结果 - 运行时的 List&lt;Long&gt; testData 由 BigInteger 实例填充,而不是由 Long 填充。结果我得到 ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long

JPA 实现 - 休眠。 作为数据库,我使用 PostgreSQL,unit.oid 字段在数据库层上具有 BigInt 类型。 在获取整个单元的情况下,它被映射到 Long,但是自定义查询为“选择不同的 ...”时出现问题,它被映射到 BigInteger。

那么,我的问题是:这种奇怪行为的原因是什么? 如何以优雅的方式解决/解决它?

【问题讨论】:

  • 这需要是nativeQuery吗?如果不是,请删除 , nativeQuery = true 看看是否有帮助。
  • @RobertNiestroj 该代码仅作为示例。实际上,“select distinct ...”更为复杂,很少有两个数据集的“select with joins”和“union”。所以,我需要使用原生查询。
  • Postgresql 中的 BigInt 映射到 BigInteger,因为它没有符号 - 你能改变你的 JPA 对象吗?
  • @farrellmr 但是在获取整个单元的情况下,oid 会正确映射到 Long。为什么?
  • 对于 nativequery 与 JPA 映射,它必须是不同的路径。一个有趣的测试是运行“select distinct(oid) from unit where oid = 1”,这样它会返回 1 个条目并将签名更改为 Long testMethod(),看看是否有效。顺便说一句,我看看您是否可以更改 Query 中的返回类型,或定义结果映射但看不到如何

标签: postgresql hibernate-mapping spring-data-jpa


【解决方案1】:

这是 Spring 数据 JPA 的问题。 如果在 DB 中数据类型被定义为 BigInteger,而在 JPA 查询中我们尝试获取为 Long 则它不会给出任何错误,但它在 Long 数据类型中将值设置为 BigInteger。

解决方案:

  1. 使用 BigInteger 作为返回类型

    @Query(value = "select distinct(oid) from unit", nativeQuery = true) List<BigInteger> testMethod();

    然后将变量设置如下。
    Long variable = bigIntegerValue.longValue();

  2. 使用 String 作为返回类型并转换为 Long

    @Query(value = "select distinct(oid) from unit", nativeQuery = true) List<String> testMethod();

    然后将值设置为

    Long variable = Long.valueOf(stringValue);

  3. 将数据库列类型更改为整数/数字。

  4. Entity 对象中获取值。

    Long variable = dpConfigData.getOid();

    dpConfigData 是 Entity(DpConfigData.class) 的对象

【讨论】:

  • 在第二种方法中,查询仍然会产生一个 BigInteger 值。因此采用第一种方法作为解决方案。
  • 谢谢,在第二种方法中出现错误 - java.math.BigInteger 无法转换为 java.lang.String
  • 这种行为是否记录在案?我认为这是一个错误,或者至少绝对令人惊讶的 WTF 行为....我想买苹果,被告知我买了苹果,但突然手里拿着橘子...
  • @FrankHopkins 这种行为没有记录在 Spring Docs 的任何地方,现在不确定文档中有什么。当我遇到错误然后调试我的代码时,我发现了这个错误。这也可以在 MYSQL DB 中找到
  • 对于那些想象“Java 怎么会允许这个错误?”的人。 *.com/q/60948445
【解决方案2】:

postgresql 中的 BigInt 映射到 BigInteger,因为它是无符号的

我认为您最好的选择是在您的 JPA 对象中将 oid 从 Long 更改为 BigInteger

【讨论】:

    【解决方案3】:

    最后我通过在“服务”层上手动映射解决了这个问题。 示例(伪代码):

    public interface TestDataRepository extends CrudRepository<DpConfigData, Long> {
            @Query(value = "select distinct(oid) from unit", nativeQuery = true)
                List<Object> testMethod();
            }
    }
    

    然后在服务层我做手动映射:

    public class TestServiceImpl extends TestService {
        pulic List<Object> testMethod(){
            List<Object> rawList = testDataRepository.testMethod();
            List<Object> resultList = new ArrayList(rawList.size());
            for(Object rw:rawList){
                resultList.add(Long.valueOf(String.valueOf(rw)));
            }
            return resultList;
        }
    }
    

    【讨论】:

    • 有趣的方法 - 另一种方法是在自定义存储库中进行转换
    【解决方案4】:

    这个问题似乎在 2.1.8 版本中得到了解决

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    

    【讨论】:

      【解决方案5】:

      您可以使用 JPQL 进行如下尝试:

      public interface TestDataRepository extends 
      JpaRepository<DpConfigData, Long> {
      @Query(value = "select distinct(u.oid) from unit u")
         List<Long> testMethod();
        }
      

      只需确保您的实体对象对于给定的属性也应该具有相同的数据类型 Long。

      【讨论】:

      • 我尝试了这个并没有解决问题。它仍在返回 BigDecimal 示例: List getUrlMappingIdListByUserIdAndRole(@Param("userId") String userId);
      最近更新 更多