美文网首页
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