java 行已被另一个事务更新或删除(或未保存值Map不正确)Spring jpa

sczxawaw  于 2023-05-12  发布在  Java
关注(0)|答案(2)|浏览(131)

我试图保存团队,然后拯救他的所有成员,但我面临着这个错误。我找了很多这个常见的问题,但我不知道问题出在哪里。
错误:

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.hackathon.web.domain.Member#com.hackathon.web.domain.MemberId@dc6]
    at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2648) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3491) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3354) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3768) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
    at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:201) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]
    at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478) ~[hibernate-core-5.4.30.Final.jar:5.4.30.Final]

团队等级:

public class Team {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="teamid")
private Long teamID;

private String name;

@ToString.Exclude
@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER,orphanRemoval = true)
@JoinColumn(name="teamid")
private List<Member> members;



@OneToMany(mappedBy = "team",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@ToString.Exclude
private Set<Mark> marks;

@ManyToOne
@JoinColumn(name = "mentorid",insertable = true, updatable = true)
@ToString.Exclude
private Mentor mentor;

@ManyToOne
@JoinColumn(name = "administratorid",insertable = true, updatable = true)
@ToString.Exclude
private Administrator administrator;

@ManyToOne
@JoinColumn(name = "hackathonid",insertable = true, updatable = true)
@ToString.Exclude
private Hackathon hackathon;}

成员类别:

public class Member {

@EmbeddedId
private MemberId id;

private String name;

private String mail;

private String lastName;

private String role;

@ManyToOne(fetch = FetchType.LAZY,cascade = ALL)
@JoinColumn(name="teamid",insertable = false, updatable = false )
private Team team;}

MemberId类:

public class MemberId implements Serializable {

@GeneratedValue(strategy = GenerationType.AUTO)
private Long memberID;

@Column(insertable=true, updatable=true)
private Long teamID;}

控制器:

@PostMapping("/administrator/addTeam")
public String saveTeam(Model model,
                      @NotNull @Valid
                       @ModelAttribute Team team,
                       BindingResult bindingResult,
                       HttpServletRequest request){

    if(team.getAdministrator() == null){
        Administrator administrator = (Administrator) request.getSession().getAttribute("user");
        team.setAdministrator(administrator);
    }

    
    Team teamForSave = new Team(0L,team.getName(),new ArrayList<>(),new HashSet<>(), team.getMentor(), team.getAdministrator(), team.getHackathon());

    Team savedTeam = teamService.save(teamForSave);

    if(team.getMembers() != null ) {
        for (Member m :
                team.getMembers()) {
            Member member = new Member(new MemberId(0L, savedTeam.getTeamID())
                    ,m.getName()
                    ,m.getMail()
                    ,m.getLastName()
                    ,m.getRole()
                    ,savedTeam);
            Member savedMember = memberService.save(member);
        }
    }
    model.addAttribute("team",savedTeam);
    return "team";
}

Hibernate日志:

Hibernate: insert into team (administratorid, hackathonid, mentorid, name) values (?, ?, ?, ?)
Hibernate: select member0_.memberid as memberid1_5_2_, member0_.teamid as teamid2_5_2_, member0_.last_name as last_nam3_5_2_, member0_.mail as mail4_5_2_, member0_.name as name5_5_2_, member0_.role as role6_5_2_, team1_.teamid as teamid1_7_0_, team1_.administratorid as administ3_7_0_, team1_.hackathonid as hackatho4_7_0_, team1_.mentorid as mentorid5_7_0_, team1_.name as name2_7_0_, marks2_.teamid as teamid2_4_4_, marks2_.markid as markid1_4_4_, marks2_.markid as markid1_4_1_, marks2_.teamid as teamid2_4_1_, marks2_.comment as comment3_4_1_, marks2_.complexity as complexi4_4_1_, marks2_.design as design5_4_1_, marks2_.efficiency as efficien6_4_1_, marks2_.judgeid as judgeid7_4_1_ from member member0_ left outer join team team1_ on member0_.teamid=team1_.teamid left outer join mark marks2_ on team1_.teamid=marks2_.teamid where member0_.memberid=? and member0_.teamid=?
Hibernate: insert into member (last_name, mail, name, role, memberid, teamid) values (?, ?, ?, ?, ?, ?)
Hibernate: update member set last_name=?, mail=?, name=?, role=? where memberid=? and teamid=?

因此,团队被正确保存,第一个成员也是,然后发生此错误。用例为:我在表单上添加新的团队,包括将成员添加到表中,为每个成员设置randomNegativeId以跟踪从表中删除,设置团队ID -1以在视图中显示正确的表单。但在这里控制器即时通讯创建新的团队和复制值,所以我不知道为什么它不工作。我试图保存所有一次与级联,但然后错误是,teamid列是空的成员。我真的需要帮助。先谢谢你了

wgx48brx

wgx48brx1#

如果使用cascade= cascadeType.all,则不应先保存团队,然后再单独保存成员。这会导致交易混乱。你应该做的是先将成员设置为teamForSave,然后保存它:

List<Member> membersForSave = new ArrayList<>();
if (team.getMembers != null) {
  for (Member m : team.getMembers()) {
        Member member = new Member(new MemberId(0L, savedTeam.getTeamID())
                ,m.getName()
                ,m.getMail()
                ,m.getLastName()
                ,m.getRole()
                ,savedTeam);

        membersForSave.add(member);
    }
}

Team teamForSave = new Team(0L, team.getName(), membersForSave, new HashSet<>(), team.getMentor(), team.getAdministrator(), team.getHackathon());

你也应该对马克做同样的事情。如果你想手动保存子实体,就像你在控制器中做的那样,删除实体(团队)中的cascadeType.All

mnowg1ta

mnowg1ta2#

首先,不要让控制器处理存储库交互,这通常是一个不好的实践。而是使用服务类。但是,如果不考虑这个问题,类就像这样

@Service
public class TeamService {
   
    private final TeamRepository teamRepo;

    public TeamService(TeamRepository teamRepo) {
        this.teamRepo = teamRepo;
    }

    public Team saveTeam(Team team) {
       team.getMembers().forEach(member -> {
           member.setMemberId(new MemberId(null, team.getTeamID()));
       });
       return teamRepo.save(team);
    }

}

就是这样由于级联设置为ALL(其中还包括PERSIST),因此将保存成员。重要的是不要手动设置id,除非它不是自动id分配策略。
您的控制器将成为

@PostMapping("/administrator/addTeam")
public String saveTeam(Model model,
                       @NotNull @Valid
                       @ModelAttribute Team team,
                       BindingResult bindingResult,
                       HttpServletRequest request){

    if(team.getAdministrator() == null){
        Administrator administrator = (Administrator) request.getSession().getAttribute("user");
        team.setAdministrator(administrator);
    }

    model.addAttribute("team", teamService.saveTeam(team));
    return "team";
}

当然,您需要注入TeamService,就像您为团队存储库所做的那样。
PS:我真的不知道teamService到底是一个Service还是一个Repositoy。如果它已经是一个服务,那么只需替换.保存()方法中的代码

相关问题