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

Spring Boot实体类字段无法同步更新至数据库问题求助

问题描述

开发Spring Boot应用时遇到实体类字段无法同步至数据库的问题:表名可正常更新,但列名、@Column注解的nullable属性、@Id的自动生成策略均未生效,具体表现为:

  • 列名被自动转为下划线格式(如firstName变为first_name)
  • 字段未设置非空约束
  • 手动插入数据时必须指定id值

已尝试刷新MySQL schema、重建数据库、重新构建Maven项目,但问题仍未解决。

User实体类代码

package com.helpinghand.HelpingHand.Backend.Model;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import javax.persistence.*;
import java.time.LocalDateTime;

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

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

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

    @Column(nullable = false)
    private String lastName;

    @Column(nullable = false)
    private String phoneNumber;

    @Column(nullable = false)
    private String streetAddress;

    @Column(nullable = false)
    private String city;

    @Column(nullable = false)
    private String state;

    @Column(nullable = false)
    private String zip;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private boolean isAdmin;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    private LocalDateTime createdDate;

    public User() {
    }

    public User(String firstName, String lastName, String phoneNumber, String streetAddress, String city, String state, String zip, String email, boolean isAdmin, LocalDateTime createDate, String password) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.phoneNumber = phoneNumber;
        this.streetAddress = streetAddress;
        this.city = city;
        this.state = state;
        this.zip = zip;
        this.email = email;
        this.isAdmin = isAdmin;
        this.createdDate = createDate;
//        this.password = password;
        setPassword(password);  // Set the hashed password
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getStreetAddress() {
        return streetAddress;
    }

    public void setStreetAddress(String streetAddress) {
        this.streetAddress = streetAddress;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getZip() {
        return zip;
    }

    public void setZip(String zip) {
        this.zip = zip;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public boolean isAdmin() {
        return isAdmin;
    }

    public void setAdmin(boolean admin) {
        isAdmin = admin;
    }

    public LocalDateTime getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(LocalDateTime createDate) {
        this.createdDate = createDate;
    }

    public String getPassword() {
        return password;
    }

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

    public void setPassword(String password) {
        // TODO: Perform password hashing here
        this.password = hashPassword(password);
    }

    private String hashPassword(String password) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.encode(password);
    }
}

application.properties配置

server.port = 8080

spring.datasource.url=jdbc:mysql://localhost:3306/helpinghand
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
#spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

#server.port=8080
#
#spring.datasource.url=jdbc:mysql://localhost:3306/helpinghand
#spring.datasource.username=root
#spring.datasource.password=
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
#spring.jpa.hibernate.ddl-auto=create-drop
#spring.jpa.show-sql=true
解决方案

1. 修复列名自动转下划线问题

Hibernate默认的物理命名策略会把实体类的驼峰字段转成下划线格式,要保留@Column指定的列名,在application.properties中添加:

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

该配置会让Hibernate严格使用你在@Column(name="xxx")里指定的列名,不再自动转换格式。

2. 修复nullable属性不生效问题

  • 若之前已创建过表,update模式不会修改已有列的约束(仅新增列或表)。可临时将spring.jpa.hibernate.ddl-auto改成create-drop,重启应用让Hibernate重建表,之后再改回update;或者手动删除数据库中的User表,用update模式重新生成。
  • 确保实体类中@Column(nullable=false)的字段未被其他全局配置覆盖。

3. 修复@Id自动生成策略不生效问题

GenerationType.AUTO在MySQL环境下可能无法正确适配自增策略,直接修改@GeneratedValue的策略:

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

此配置会让Hibernate使用MySQL的自增主键机制,插入数据时无需手动指定id,数据库会自动生成。若之前表已存在,需手动将id列改成AUTO_INCREMENT类型,或重建表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 22:15:10