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

Spring Boot JPA findById()重启应用后失效问题求助

问题描述

首次启动应用时,数据库无对应表,Spring自动创建表,此时save()、findById()等操作均正常。但重启应用后,首次执行findById()语句时应用卡住,无后续响应。

使用技术栈

  • Spring Boot 3.0.1
  • MariaDB 10.9
  • Java 17

相关代码

pom.xml

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

<dependencies>
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.mariadb.jdbc</groupId>
        <artifactId>mariadb-java-client</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    .
    .
    .
</dependencies>

application.properties

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mariadb://${MYSQL_HOST:localhost}:3306/database
spring.datasource.username=USERNAME
spring.datasource.password=PASSWORD
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.jpa.open-in-view=false

Entity类(GuildEntity)

@Entity
@Table(name = "guild_entity")
@Getter
@Setter
public class GuildEntity {

    @Id
    @Column(name = "guild_id")
    private String guildId;

    @Column(name = "bot_control_role")
    private String botControlRole;

    @Column(name = "command_prefix")
    @Builder.Default
    private String commandPrefix = "varchar(1) default '&'";

    @Column(name = "language")
    @Builder.Default
    private String language = "varchar(2) default 'EN'";

    @Column(name = "voice_control_role")
    private String voiceControlRole;

    @Column(name = "volume")
    @Builder.Default
    private Integer volume = 20;

    @Column(name = "player_shuffle")
    @Builder.Default
    private Boolean shuffle = false;

    @Column(name = "player_repeat")
    @Builder.Default
    private Boolean repeat = false;

    @Column(name = "write_channel")
    private String writeChannel;

    @Column(name = "enable_support_system")
    @Builder.Default
    private Boolean enableSupportSystem = false;

    @Column(name = "enable_welcome_messages")
    @Builder.Default
    private Boolean enableWelcomeMessages = false;

    @Column(name = "welcome_channel")
    private String welcomeChannel;

    @Column(name = "welcome_message")
    @Builder.Default
    private String welcomeMessage = "varchar(255) default ':wave: Welcome to %server%, %user%!'";
}

EntityRepository接口

@Repository
public interface GuildEntityRepository extends JpaRepository<GuildEntity, String> {

}

SQLHandler服务类

@Service
@RequiredArgsConstructor
public class SQLHandler {

    @Autowired
    private final GuildEntityRepository guildEntityRepository;

    public GuildEntity getGuild(String guildId) {
        NeptuneBot.getLogger().debug(guildId, "Get guild", LogType.SQL);
        return guildEntityRepository.findById(guildId).orElse(null);
    }

    public void saveAllGuilds(Iterable<GuildEntity> guildEntities) {
        NeptuneBot.getLogger().debugSQL("Save all guild entities...");
        guildEntityRepository.saveAll(guildEntities);
        NeptuneBot.getLogger().debugSQL("Done!");
    }
}

重启后的日志

[2m2022-12-31T03:07:38.523+01:00[0;39m [32m INFO[0;39m [35m1751594[0;39m [2m---[0;39m [2m[0.1-8080-exec-1][0;39m [36mo.a.c.c.C.[Tomcat].[localhost].[/]      [0;39m [2m:[0;39m Initializing Spring DispatcherServlet 'dispatcherServlet'
    [2m2022-12-31T03:07:38.523+01:00[0;39m [32m INFO[0;39m [35m1751594[0;39m [2m---[0;39m [2m[0.1-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet       [0;39m [2m:[0;39m Initializing Servlet 'dispatcherServlet'
    [2m2022-12-31T03:07:38.525+01:00[0;39m [32m INFO[0;39m [35m1751594[0;39m [2m---[0;39m [2m[0.1-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet       [0;39m [2m:[0;39m Completed initialization in 1 ms
    [2m2022-12-31T03:07:38.907+01:00[0;39m [32m INFO[0;39m [35m1751594[0;39m [2m---[0;39m [2m[           main][0;39m [36mnet.dv8tion.jda.api.JDA                 [0;39m [2m:[0;39m Login Successful!
    [2m2022-12-31T03:07:39.198+01:00[0;39m [32m INFO[0;39m [35m1751594[0;39m [2m---[0;39m [2m[inWS-ReadThread][0;39m [36mn.d.j.internal.requests.WebSocketClient [0;39m [2m:[0;39m Connected to WebSocket
    [2m2022-12-31T03:07:39.608+01:00[0;39m [32m INFO[0;39m [35m1751594[0;39m [2m---[0;39m [2m[inWS-ReadThread][0;39m [36mnet.dv8tion.jda.api.JDA                 [0;39m [2m:[0;39m Finished Loading!
    [2022.12.31 03:07:42]: SQL | Get guild
    Hibernate: 
        select
            g1_0.guild_id,
            g1_0.bot_control_role,
            g1_0.command_prefix,
            g1_0.enable_support_system,
            g1_0.enable_welcome_messages,
            g1_0.language,
            g1_0.player_repeat,
            g1_0.player_shuffle,
            g1_0.voice_control_role,
            g1_0.volume,
            g1_0.welcome_channel,
            g1_0.welcome_message,
            g1_0.write_channel 
        from
            guild_entity g1_0 
        where
            g1_0.guild_id=?

问题分析与解决方案

核心问题定位

问题出在Entity类的默认值配置错误:

  • GuildEntity中commandPrefix、language、welcomeMessage字段的@Builder.Default注解后,赋值的是SQL字段定义语句(如"varchar(1) default '&'"),而非实际业务默认值。
  • 首次启动建表时,Hibernate会将这些字符串当作字段默认值写入表结构;但重启后查询时,错误的默认值会干扰Hibernate的元数据校验,触发首次查询时的线程阻塞或无限等待。

具体修复步骤

  1. 修正Entity类默认值
    将错误的SQL语句替换为实际业务值,若需数据库层面的默认值,通过@Column的columnDefinition配置:

    @Column(name = "command_prefix", columnDefinition = "varchar(1) default '&'")
    @Builder.Default
    private String commandPrefix = "&";
    
    @Column(name = "language", columnDefinition = "varchar(2) default 'EN'")
    @Builder.Default
    private String language = "EN";
    
    @Column(name = "welcome_message", columnDefinition = "varchar(255) default ':wave: Welcome to %server%, %user%!'")
    @Builder.Default
    private String welcomeMessage = ":wave: Welcome to %server%, %user%!";
    
  2. 重建数据库表
    手动删除guild_entity表,或临时将spring.jpa.hibernate.ddl-auto改为create,启动一次应用后改回update,确保表结构正确。

  3. 优化数据库连接配置
    给连接URL添加必要参数,避免时区、SSL等问题导致连接阻塞:

    spring.datasource.url=jdbc:mariadb://${MYSQL_HOST:localhost}:3306/database?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
    
  4. 排查线程阻塞
    应用卡住时用jstack命令查看线程堆栈,若为连接池问题,调整连接池参数:

    spring.datasource.hikari.maximum-pool-size=10
    spring.datasource.hikari.connection-timeout=30000
    

验证效果

修复后重启应用,首次findById()操作可正常执行,无阻塞情况,后续操作也能稳定运行。


内容的提问来源于stack exchange,提问作者Jes Müller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:15:37