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)
问题原因分析
- MySQL表名大小写敏感性:Linux系统下MySQL默认区分表名大小写(
lower_case_table_names=0),而Hibernate默认会将实体对应的表名转为小写,导致无法匹配原有的Track和User表,进而创建新的小写表。 - Hibernate命名策略:默认的命名策略会自动转换表名格式,即使你在
@Table注解中指定了大写表名,也可能被覆盖。 - 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
相关产品推荐
相关产品推荐

