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

Spring应用执行无结果SQLite查询时崩溃,求解决方案

解决SQLite查询无结果导致应用崩溃的问题

问题场景

使用SQLite数据库时,执行预期无结果的查询会导致应用崩溃,但切换到MariaDB时无此异常。

报错信息

2022-08-10 16:10:47.160  WARN 15512 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: null
2022-08-10 16:10:47.160 ERROR 15512 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper   : Query does not return results
2022-08-10 16:10:47.207 ERROR 15512 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet] with root cause

相关代码

查询语句

@Query(value = "SELECT * FROM Port WHERE user_id=:userId", nativeQuery = true)
Port checkIfUserHasPort(@Param("userId") Long userId);

Port实体

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Port {
    @Id
    private int port;
    private boolean active;
    private LocalDateTime expiration;
    @OneToOne
    @JoinColumn(name="id")
    private User user;
}

User实体

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "id_Sequence")
    @SequenceGenerator(name = "id_Sequence", sequenceName = "ID_SEQ")
    private Long id;
    @JsonIgnore
    private String username;
    @JsonIgnore
    private String password;
    @JsonIgnore
    @OneToOne(mappedBy = "user")
    private Port port;
    @JsonIgnore
    @ManyToMany(fetch = EAGER)
    private Collection<Role> roles = new ArrayList<>();
    @JsonIgnore
    @OneToMany(mappedBy = "user")
    private Set<Log> logs=new HashSet<>();
}

解决方案

1. 修改方法返回类型为Optional<Port>

原方法直接返回Port,当查询无结果时,SQLite的JDBC驱动会抛出无结果异常,而MariaDB会返回null,导致数据库间行为差异。将返回类型改为Optional<Port>,Hibernate会在无结果时返回Optional.empty(),避免抛出异常:

@Query(value = "SELECT * FROM Port WHERE user_id=:userId", nativeQuery = true)
Optional<Port> checkIfUserHasPort(@Param("userId") Long userId);

调用时通过Optional的API处理结果:

Optional<Port> portOpt = portRepository.checkIfUserHasPort(userId);
if (portOpt.isPresent()) {
    Port port = portOpt.get();
    // 存在端口的业务逻辑
} else {
    // 无端口的业务逻辑
}

2. 替换原生SQL为JPA查询

使用JPA查询而非原生SQL,让Hibernate自动适配不同数据库的语法和结果处理逻辑,消除数据库差异带来的问题:

@Query("SELECT p FROM Port p WHERE p.user.id = :userId")
Optional<Port> checkIfUserHasPort(@Param("userId") Long userId);

3. 更新SQLite JDBC驱动版本

部分旧版本的SQLite JDBC驱动对无结果集的处理存在兼容性bug,更新到最新稳定版(如xerial/sqlite-jdbc的最新版)可解决此类问题。

4. 正确捕获异常(可选)

若必须保留原返回类型,需确保捕获正确的异常类型。原try-catch无效大概率是因为捕获范围不对,应捕获JpaSystemException或其上层的RuntimeException:

try {
    Port port = portRepository.checkIfUserHasPort(userId);
    // 结果处理逻辑
} catch (JpaSystemException e) {
    // 处理无结果或JPA相关异常
}

此方案优先级低于前两种,仅作为临时兼容方案使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 00:18:19