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

POST创建User触发StaleObjectStateException错误排查求助

问题描述

通过Postman调用getUsers接口(GET请求)一切正常,但调用创建用户接口(POST请求)时抛出异常,无法将User写入数据库。

错误信息

ERROR 7388 --- [myApiPortifolio] [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.orm.ObjectOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.myapps.myApiPortifolio.entities.User#0eb358b8-93d9-4fe1-a457-8a186d0788aa]] with root cause org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect):


相关代码

User 实体类

package com.myapps.myApiPortifolio.entities;

import jakarta.persistence.*;

import java.util.List;
import java.util.UUID;

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

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

    private String username;
    private String email;
    private String password;

    @OneToMany(mappedBy = "user")
    private List<Account> accounts;

    public User() {
    }

    public User(UUID id, String username, String email, String password) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.password = password;
    }

    public UUID getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

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

    public String getPassword() {
        return password;
    }

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

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }
}

Account 实体类

package com.myapps.myApiPortifolio.entities;

import jakarta.persistence.*;

import java.util.UUID;

@Entity
@Table(name = "tb_accounts")
public class Account {

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

    private String accountType;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;


    public Account() {
    }

    public Account(UUID id, String accountType) {
        this.id = id;
        this.accountType = accountType;
    }

    public UUID getId() {
        return id;
    }

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

    public String getAccountType() {
        return accountType;
    }

    public void setAccountType(String accountType) {
        this.accountType = accountType;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

CreateUserDto

package com.myapps.myApiPortifolio.entities.dtos;

public record CreateUserDto(String username, String email, String password) {
}

UserRepository

package com.myapps.myApiPortifolio.repositories;

import com.myapps.myApiPortifolio.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repository
public interface UserRepository extends JpaRepository<User, UUID> {
}

UserService

package com.myapps.myApiPortifolio.services;

import com.myapps.myApiPortifolio.entities.User;
import com.myapps.myApiPortifolio.entities.dtos.CreateUserDto;
import com.myapps.myApiPortifolio.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

@Service
public class UserService {

    @Autowired
    UserRepository userRepository;

    public UUID createUser(CreateUserDto createUserDto) {

        // DTO -> ENTITY
        User user = new User(
                UUID.randomUUID(),
                createUserDto.username(),
                createUserDto.email(),
                createUserDto.password()
        );

        var createdUser = userRepository.save(user);
        return createdUser.getId();
    }

    public List<User> getUsers() {
        return userRepository.findAll();
    }
}

UserController

package com.myapps.myApiPortifolio.controllers;


import com.myapps.myApiPortifolio.entities.User;
import com.myapps.myApiPortifolio.entities.dtos.CreateUserDto;
import com.myapps.myApiPortifolio.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    UserService userService;

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody CreateUserDto createUserDto) {

        var userId = userService.createUser(createUserDto);

        return ResponseEntity.created(URI.create("/users/" + userId)).build();
    }

    @GetMapping
    public ResponseEntity<List<User>> getUsers() {

        var users =  userService.getUsers();

        return ResponseEntity.ok(users);
    }
}

问题原因及解决方案

原因

你在UserService的createUser方法中手动生成UUID作为User的ID,但User实体类的ID配置了@GeneratedValue(strategy = GenerationType.AUTO),这会让Hibernate尝试再次生成ID,或者误以为你传入的ID对应的记录已存在(比如数据库中残留了相同UUID的旧记录),最终触发乐观锁异常。

解决方案

修改UserService的createUser方法,不要手动传入UUID,改用无参构造器创建实例后设置属性:

public UUID createUser(CreateUserDto createUserDto) {
    // DTO -> ENTITY
    User user = new User();
    user.setUsername(createUserDto.username());
    user.setEmail(createUserDto.email());
    user.setPassword(createUserDto.password());

    var createdUser = userRepository.save(user);
    return createdUser.getId();
}

或者在User实体类中新增不含ID的构造器,直接调用:

// 先在User类中新增构造器:
// public User(String username, String email, String password) {
//     this.username = username;
//     this.email = email;
//     this.password = password;
// }

// 然后修改service中的代码:
User user = new User(createUserDto.username(), createUserDto.email(), createUserDto.password());

另外,建议清空tb_users表的旧数据后再重新测试,避免残留数据干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:48:12