You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot @Query查询返回Null及NPE问题排查求助

解决Spring Boot @Query返回Null及NPE问题的分步排查方案

看起来你现在卡在两个关键问题上:调用Service层的getDenda时触发NullPointerException,而且日志压根没执行;另外明明数据库有匹配数据,@Query却一直返回Null。我来帮你一步步拆解排查,先解决最紧急的NPE问题,再搞定查询的事儿:

一、先搞定Service层的NPE问题

你说调用getDenda时触发NPE且日志没执行,这几乎可以肯定是Service实例没被Spring正确注入,或者你手动new了Service对象(手动new的对象不受Spring管理,里面的Repository也不会被注入,直接就Null了)。按以下步骤检查:

  • 确认你的Service类上加了@Service注解,Controller里用构造函数注入(推荐)或者@Autowired注入,绝对不要手动new Service:
    // 正确的Service写法,加@Service让Spring管理
    @Service
    public class TransaksiService {
        private final DataTransaksiRepository transaksiRepo;
        
        // 构造函数注入,Spring会自动把Repository实例传进来
        public TransaksiService(DataTransaksiRepository transaksiRepo) {
            this.transaksiRepo = transaksiRepo;
        }
        
        public String getDenda(String tanggal, String namaWp, String masaPajak) {
            // 先加个日志,确认方法能进入
            System.out.println("进入getDenda方法,参数:tanggal=" + tanggal + ", namaWp=" + namaWp + ", masaPajak=" + masaPajak);
            return transaksiRepo.findAllDenda(tanggal, namaWp, masaPajak);
        }
    }
    
    // Controller里正确注入Service
    @RestController
    public class TransaksiController {
        private final TransaksiService transaksiService;
        
        // 同样用构造函数注入,避免依赖注入的坑
        public TransaksiController(TransaksiService transaksiService) {
            this.transaksiService = transaksiService;
        }
        
        // CSV上传接口示例
        @PostMapping("/upload-csv")
        public ResponseEntity<?> handleCsvUpload(@RequestParam("file") MultipartFile file) {
            // 解析CSV拿到参数x,y,z
            String x = "从CSV解析的tanggal";
            String y = "从CSV解析的nama_wp";
            String z = "从CSV解析的masa_pajak";
            
            // 这里调用Service,不会再NPE了
            String denda = transaksiService.getDenda(x, y, z);
            // ...后续逻辑
        }
    }
    
  • 启动Spring Boot时盯着控制台日志,看看有没有Bean创建失败的异常,比如找不到Repository或者Service的定义,有的话先解决这个。

二、排查@Query返回Null的问题

等Service能正常调用、日志能打印后,再来解决查询返回Null的问题,按以下步骤来:

1. 先修正返回值类型

你说预期返回的是denda字段的集合,但你的方法返回类型是String——这就错了!如果查询到多条数据,Spring会直接抛异常;如果没匹配到(或者类型不兼容)就返回Null。改成List<String>才对:

@Query(value = "select d.denda from data_transaksi_model d WHERE d.tanggal=:x AND d.nama_wp = :y AND d.masa_pajak=:z", nativeQuery = true)
List<String> findAllDenda(String x,String y,String z);

如果确认只会有一条匹配数据,用Optional<String>更安全,避免Null:

Optional<String> findAllDenda(String x,String y,String z);

2. 对比实际执行的SQL和手动执行的SQL

你说手动执行SQL能拿到结果,但Spring里不行,最大的可能是参数传递有问题。开启Spring Data JPA的SQL日志,看看实际执行的SQL和参数值:
application.properties里加这几行:

# 打印SQL语句
spring.jpa.show-sql=true
# 格式化SQL,方便查看
spring.jpa.properties.hibernate.format_sql=true
# 打印参数值
logging.level.org.hibernate.type.descriptor.sql=trace

启动项目后调用接口,控制台会输出完整的SQL和参数,和你手动在MySQL里执行的对比:

  • 检查tanggal的格式:比如数据库里是'2024-05-20',但你从CSV解析的是'20/05/2024',格式不匹配就查不到;
  • 检查参数有没有空格:比如nama_wp数据库里是"张三",但你传递的是" 张三 ",带空格就匹配不到,解析CSV后记得给参数做trim()处理;
  • 检查参数类型:比如数据库里tanggal是DATE类型,你传递的是String,格式不对也会匹配失败,必要的话把参数转成LocalDate再传递。

3. 处理IntelliJ的警告

这两个警告不会直接导致查询失败,但配置好能避免潜在问题:

  • 未配置数据源以运行SQL并提供高级代码辅助:打开IntelliJ的Database工具窗口,添加你的XAMPP MySQL数据源,连接上之后IntelliJ就能识别表和字段,给你SQL语法检查和补全;
  • 未配置SQL方言:在application.properties里指定MySQL的方言,根据你的MySQL版本选:
    # MySQL 8.x用这个
    spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
    # MySQL 5.x用这个
    # spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
    

三、最后再检查实体类映射

虽然你说表名、列名、类型都匹配,但再确认一遍DataTransaksiModel的注解:

@Entity
@Table(name = "data_transaksi_model") // 确认表名和数据库一致
public class DataTransaksiModel {
    @Column(name = "tanggal")
    private LocalDate tanggal; // 和数据库的DATE类型对应,要是数据库是VARCHAR就用String
    
    @Column(name = "nama_wp")
    private String namaWp; // 列名要和数据库完全一致,注意下划线
    
    @Column(name = "masa_pajak")
    private String masaPajak;
    
    @Column(name = "denda")
    private String denda;
    
    // getter和setter一定要有,不然Spring无法映射
}

一步步来,先解决NPE的问题,再通过日志对比SQL,很快就能找到问题所在了。

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

火山引擎 最新活动