为何重启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); } } }
原因分析
问题根源在于:
- User实体类被标记为@Component:Spring启动时会自动创建该类的实例并纳入容器管理,而Hibernate会将这个Spring创建的实体实例持久化到数据库,导致每次启动插入默认数据。
- 控制器和服务类中注入了User实例:
@Autowired User returnUser和@Autowired User tempUser完全没有必要,这些注入的实例同样会被Hibernate误持久化。
解决方案
- 移除User类上的
@Component注解:JPA实体不需要被Spring容器管理,Hibernate会自行处理实体的实例化。 - 删除控制器和服务类中所有@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
相关产品推荐
相关产品推荐

