美文网首页
bug之 JPA采用原生sql查询 BigInteger can

bug之 JPA采用原生sql查询 BigInteger can

作者: Albert_zheng | 来源:发表于2018-04-15 22:48 被阅读0次

在这周对代码进行重构时,发现了一个很隐晦的bug,我认为很有必要把它记下来。产生bug详细流程如下:

  1. 首先我是采用JPA提供的执行原生sql语句的方式去查询一个ID,这个ID在数据库的类型为bigint。查询方式如下:
@Query(nativeQuery = true,
            value = "SELECT car_id FROM cars WHERE car_id IN (?1)")
List<Long> findCarIdsByCars(List<Long> carIds);

调用方式:

public List<Long> getCarIdByCars(List<Long> vehicleIds) {
    List<Long> list = quotationRepository.findCarIdsByCars(vehicleIds);
    return longList;
}

这个查询的目的是返回数据库已存在的指定ID。从SQL语句看是没有任何问题的,但是当我通过debug调用这个repository会发现如下内容:

debug时list内的值
显然,List的值竟然是BigInteger的,而我们上面写的明明是List<Long>,而且这种时候编译器也是没有报错的,明明对象的类型就是不对的!

寻找原因

通过google搜索发现,JPA内部查询是通过createSQLQuery和createQuery实现的。所有的查询都会调用这两个方法。它们的不同点是:

  1. createQuery用的JPQL语句进行查询,createSQLQuery用sql语句查询;
  2. 前者以hibernate生成的Bean为对象装入list返回;后者则是以对象数组进行存储;
  3. 当通过createSQLQuery查询时,如果存在Bean的实例,则它会按照实例去返回,但是当实例不存在时它会按照JPA给定的默认配置去返回映射值,而bigint的映射正是BigInteger,所以才会出现如上情况。

解决办法

解决办法有两种,一种是修改repository的返回方式为BigInteger,但是这样的话还需要调用代码去转换,而且可读性也不太好。所以建议采用第二种解决办法:
使用JPQL(Java Persistence Query Language)语言去写返回值。实现方式如下:

@Query("SELECT c.carId FROM cars c WHERE c.carId IN (?1)")
List<Long> findCarIdsByCars(List<Long> carIds);

这样写JPA会完美map返回值,其实跟写原生sql是一样的。另外个人觉得还是尽量用JPQL语句进行数据库操作比较好,因为JPA的存在一个重要的原因就是为了JAVA与数据库之间的解耦,我们通过JPQL语言可以很好地将table与java代码之间的耦合分离开来。何乐而不为呢?

相关文章

网友评论

      本文标题:bug之 JPA采用原生sql查询 BigInteger can

      本文链接:https://www.haomeiwen.com/subject/jwhdkftx.html