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

为何重启Spring Boot时H2数据库会自动插入默认值行?

问题描述

每次重启Spring Boot应用时,H2数据库的Users实体都会自动插入一条包含默认值的数据行。相关代码及配置如下:

User实体类

@Component
@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity(name = "Users")
@Table(name = "Users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="userId")
    private int id;
    @Column(unique=true)
    private String username = "";
    private String city = "";
    private String state = "";
    private String zip = "";
    private boolean peanutAll = false;
    private boolean eggAll = false;
    private boolean dairyAll = false;
}

配置文件

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:dcbapp;DATABASE_TO_UPPER=false;
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.hibernate.ddl-auto=update

UserController

@RestController
@RequestMapping(path="/user")
public class UserController {
    @Autowired UserService userv;
    @Autowired User returnUser;
    
    @PostMapping("/add")
    public ResponseEntity<User> addUser(@Valid @RequestBody User user){
    Optional<User> tempUser =   Optional.ofNullable(userv.addUser(user));
    return ResponseEntity.of(tempUser);
    }
    
    @PutMapping("/update")
    public ResponseEntity<User> updateUser(@Valid @RequestBody User user){
        User tempUser = userv.updateUser(user);
        return ResponseEntity.ok(tempUser);
    }
    
    @GetMapping("/{username}")
    public ResponseEntity<User> getUser(@PathVariable(value="username") String username ){
        User tempUser = userv.getUserByUsername(username);
        return ResponseEntity.ok(tempUser);
    }
}

UserService

@Service
public class UserService {

    @Autowired UserRepo userRepo;
    @Autowired User tempUser;
    @Autowired 
    
    public User addUser(User user) {
        if(userRepo.existsById(user.getId())) {
            throw new UserAlreadyExistsException(String.format("User %s already exists", user.getUsername()));
        }

        else {
                return userRepo.save(user);
            }       
        }
    
    public User getUserByUsername(String username) {        
        User tempUser = userRepo.findByUsername(username).orElseThrow(() -> new UserNotFoundException(String.format("User doesn't exist: %s", username)));      
        return tempUser;
    }
    
    public User getUserById(int id) {
        User tempUser = userRepo.findById(id).orElseThrow(() -> new UserNotFoundException(String.format("User doesn't exist with id: %d", id)));
        return tempUser;
    }
    
    //you need to include id in json body request
    public User updateUser(User user) throws UserNotFoundException, ChangeUsernameException, MustMakeChangeException{
        Optional<User> tempUser1 = userRepo.findById(user.getId());
        if(tempUser1.isEmpty()) {
            throw new UserNotFoundException(String.format("User doesn't exist: %s", user.getUsername()));
        }
        User tempUser = tempUser1.get();
        
        if(!tempUser.getUsername().equals(user.getUsername())) {
            throw new ChangeUsernameException(String.format("Unable to change username: %s", user.getUsername()));
        }
        else if(tempUser.getCity().equals(user.getCity()) && tempUser.getState().equals(user.getState()) && tempUser.getZip().equals(user.getZip())) {
            
            throw new MustMakeChangeException("You must make an update to user");
        }
        else {
            
            return userRepo.save(user);
        }
    }
}
原因分析

问题根源在于:

  1. User实体类被标记为@Component:Spring启动时会自动创建该类的实例并纳入容器管理,而Hibernate会将这个Spring创建的实体实例持久化到数据库,导致每次启动插入默认数据。
  2. 控制器和服务类中注入了User实例:@Autowired User returnUser和@Autowired User tempUser完全没有必要,这些注入的实例同样会被Hibernate误持久化。
解决方案
  1. 移除User类上的@Component注解:JPA实体不需要被Spring容器管理,Hibernate会自行处理实体的实例化。
  2. 删除控制器和服务类中所有@Autowired的User实例:方法内的User变量应作为局部变量使用,无需依赖Spring注入。
修正后的代码示例

修正后的User实体类

@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity(name = "Users")
@Table(name = "Users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="userId")
    private int id;
    @Column(unique=true)
    private String username = "";
    private String city = "";
    private String state = "";
    private String zip = "";
    private boolean peanutAll = false;
    private boolean eggAll = false;
    private boolean dairyAll = false;
}

修正后的UserController

@RestController
@RequestMapping(path="/user")
public class UserController {
    @Autowired UserService userv;
    
    @PostMapping("/add")
    public ResponseEntity<User> addUser(@Valid @RequestBody User user){
        Optional<User> tempUser = Optional.ofNullable(userv.addUser(user));
        return ResponseEntity.of(tempUser);
    }
    
    @PutMapping("/update")
    public ResponseEntity<User> updateUser(@Valid @RequestBody User user){
        User tempUser = userv.updateUser(user);
        return ResponseEntity.ok(tempUser);
    }
    
    @GetMapping("/{username}")
    public ResponseEntity<User> getUser(@PathVariable(value="username") String username ){
        User tempUser = userv.getUserByUsername(username);
        return ResponseEntity.ok(tempUser);
    }
}

修正后的UserService

@Service
public class UserService {

    @Autowired UserRepo userRepo;
    
    public User addUser(User user) {
        if(userRepo.existsById(user.getId())) {
            throw new UserAlreadyExistsException(String.format("User %s already exists", user.getUsername()));
        } else {
            return userRepo.save(user);
        }       
    }
    
    public User getUserByUsername(String username) {        
        User tempUser = userRepo.findByUsername(username).orElseThrow(() -> new UserNotFoundException(String.format("User doesn't exist: %s", username)));      
        return tempUser;
    }
    
    public User getUserById(int id) {
        User tempUser = userRepo.findById(id).orElseThrow(() -> new UserNotFoundException(String.format("User doesn't exist with id: %d", id)));
        return tempUser;
    }
    
    // 需要在JSON请求体中包含id
    public User updateUser(User user) throws UserNotFoundException, ChangeUsernameException, MustMakeChangeException{
        Optional<User> tempUser1 = userRepo.findById(user.getId());
        if(tempUser1.isEmpty()) {
            throw new UserNotFoundException(String.format("User doesn't exist: %s", user.getUsername()));
        }
        User tempUser = tempUser1.get();
        
        if(!tempUser.getUsername().equals(user.getUsername())) {
            throw new ChangeUsernameException(String.format("Unable to change username: %s", user.getUsername()));
        } else if(tempUser.getCity().equals(user.getCity()) && tempUser.getState().equals(user.getState()) && tempUser.getZip().equals(user.getZip())) {
            throw new MustMakeChangeException("You must make an update to user");
        } else {
            return userRepo.save(user);
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:55:24