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

Java Spring用户注册时user表插入两条记录而非一条问题排查

问题根因

返回值username为null

你的Login和User是双向关联实体,且做了属性同步逻辑:当调用Login.setUsername(null)时,会同步修改关联User对象的username属性为null。你的代码里先后在两处执行了Login.setUsername(null)操作,直接把传入的User对象的username改成了null,最终构造返回值时自然拿到null。

生成两条User记录

Login实体对关联的User属性配置了CascadeType.PERSIST或CascadeType.ALL级联持久化规则:

  1. 你在registerNewUser中手动调用userRepository.save(user)生成了第一条ID=1的符合预期的记录
  2. 因为confirmToken方法加了@Transactional注解,方法执行结束后持久化上下文会自动flush,此时托管状态的Login对象关联的是临时状态的User对象,触发级联保存生成了第二条ID=2的多余记录,且此时username已经被改为null,所以第二条记录的username字段为null。

修复方案

  1. 移除冗余的Login.setUsername操作,删掉上层confirmToken方法中的confirmationToken.getLogin().setUsername(null);这行代码,只在registerNewUser中修改一次即可
  2. 调整registerNewUser的执行顺序,先保存用户,再修改Login属性,同时把Login关联的User设置为已经持久化的对象,避免触发级联保存:
public RegistrationConfirmResponse registerNewUser(User user, String password) {
    // 先查对应的login记录
    Login login = loginRepository.findByUsername(user.getUsername()).get();
    // 保存用户拿到持久化状态的对象
    User savedUser = userRepository.save(user);
    passwordRepository.save(new Password(savedUser.getUserId(), password));
    // 给login设置已持久化的user对象,避免级联生成新记录
    login.setUser(savedUser);
    // 最后修改login的username,避免提前修改导致查询失败
    login.setUsername(null);
    // 用已保存的user的username构造返回值
    return new RegistrationConfirmResponse("done", savedUser.getUsername());
}
  1. 如果不需要Login级联保存User,可以直接移除Login实体中User关联的CascadeType.PERSIST/CascadeType.ALL配置,从根源避免多余记录生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 19:06:02