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

Spring Boot应用重复创建MySQL已有表,请求解决方案

问题描述

我在MySQL中有一个名为newdb的数据库,里面已经存在Track和User两张表。但启动Spring Boot应用时,系统会自动创建小写的track和user新表,并且使用这些新表而非数据库中原有的表。我希望应用停止创建新表,直接使用已有的两张表。

相关代码与配置信息如下:

Track.java

package net.codejava.song.model;

import org.hibernate.annotations.NaturalId;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import java.sql.Timestamp;
import java.time.LocalDateTime;

@Entity
@Table(name = "Track")
public class Track {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "isrc", unique = true, nullable = false, length = 20)
    private String isrc;

    @Column(name = "name", nullable = false, length = 100)
    private String name;

    @Column(name = "duration_ms", nullable = false)
    private Long durationMs;

    @Column(name = "explicit", nullable = false)
    private Boolean explicit;

    @Column(name = "created_at", nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    private LocalDateTime createdAt;

    public String getIsrc() {
        return isrc;
    }

    public void setIsrc(String isrc) {
        this.isrc = isrc;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getDurationMs() {
        return durationMs;
    }

    public void setDurationMs(Long durationMs) {
        this.durationMs = durationMs;
    }

    public Boolean getExplicit() {
        return explicit;
    }

    public void setExplicit(Boolean explicit) {
        this.explicit = explicit;
    }

    // default constructor for JPA
    public Track() {
        this.createdAt = LocalDateTime.now();

    }

    // constructor with arguments
    public Track(String isrc, String name, Long durationMs, Boolean explicit) {
        this.isrc = isrc;
        this.name = name;
        this.durationMs = durationMs;
        this.explicit = explicit;
        
    }

}

User.java

@Entity
@Table(name = "User")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "username", unique = true, nullable = false, length = 50)
    private String username;

    @Column(name = "password", nullable = false, length = 255)
    private String password;

    // default constructor for JPA
    protected User() {}

    // constructor with arguments
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    // getters and setters
    
    
}

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/newdb
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# JPA properties
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.5</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>net.codejava.song</groupId>
    <artifactId>RestAPI-MetaData</artifactId>
    <version>1.0</version>
    <name>RestAPI-MetaData</name>
    <description>A REST-API for storing metadata of music tracks to a Relational Database, fetching the metadata from a mock endpoint.</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents.client5</groupId>
            <artifactId>httpclient5</artifactId>
            <version>5.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.mock-server</groupId>
            <artifactId>mockserver-netty</artifactId>
            <version>3.10.8</version>
        </dependency>
        <dependency>
            <groupId>org.mock-server</groupId>
            <artifactId>mockserver-client-java</artifactId>
            <version>3.10.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-hateoas</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>3.0.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.github.tomakehurst</groupId>
            <artifactId>wiremock-jre8</artifactId>
            <version>2.27.2</version>
            <scope>test</scope>
        </dependency>
        <!-- Spring dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- MySQL dependency -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.32</version>
        </dependency>
        <!-- JSON Web Token (JWT) dependency -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>
        <!-- Lombok dependency -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

表创建日志输出

Hibernate: drop table if exists track
Hibernate: drop table if exists user
Hibernate: create table track (id integer not null auto_increment, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP not null, duration_ms bigint not null, explicit bit not null, isrc varchar(20) not null, name varchar(100) not null, primary key (id)) engine=InnoDB
Hibernate: create table user (id integer not null auto_increment, password varchar(255) not null, username varchar(50) not null, primary key (id)) engine=InnoDB
Hibernate: alter table track add constraint UK_eeljh0fjup9osa3cp6h9wqtgv unique (isrc)
Hibernate: alter table user add constraint UK_sb8bbouer5wak8vyiiy4pf2bx unique (username)

问题原因分析
  1. MySQL表名大小写敏感性:Linux系统下MySQL默认区分表名大小写(lower_case_table_names=0),而Hibernate默认会将实体对应的表名转为小写,导致无法匹配原有的Track和User表,进而创建新的小写表。
  2. Hibernate命名策略:默认的命名策略会自动转换表名格式,即使你在@Table注解中指定了大写表名,也可能被覆盖。
  3. DDL自动配置:spring.jpa.hibernate.ddl-auto=update会让Hibernate根据实体结构自动更新或创建表,当找不到匹配表时就会新建。

解决方案

方案1:修改MySQL大小写配置(Linux系统适用)

  • 找到MySQL配置文件(通常为/etc/my.cnf或/etc/mysql/my.cnf)
  • 添加或修改配置:
    lower_case_table_names=1
    
  • 重启MySQL服务。此配置会让MySQL将所有表名转为小写存储,查询时不区分大小写,这样Hibernate的小写表名就能匹配原有表(注意:修改前需确保现有表名已统一为小写,或备份后重新导入)。

方案2:配置Hibernate保留指定表名大小写

在application.properties中添加以下配置,强制Hibernate完全使用@Table注解中指定的表名,不做任何转换:

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

该策略会严格保留你设置的表名大小写,避免自动转换。

方案3:禁用Hibernate自动DDL操作

如果数据库表结构完全匹配实体类,可将ddl-auto设置为none,禁止Hibernate创建或修改表:

spring.jpa.hibernate.ddl-auto=none

注意:设置后,后续实体类的修改需要手动同步到数据库表中。


验证修改

重启Spring Boot应用,查看日志是否不再出现创建track和user表的SQL语句,且应用能正常操作原有的Track和User表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 15:17:01