假设我有一个单向的@ManyToOne关系,如下所示:
@Entity
@Table(name = "TestUser")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class TestUser {
@Id
@Column(nullable = false)
private String id;
@Column(name = "some_property")
private String someProperty;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TestUser)) return false;
return id != null && id.equals(((TestUser) o).getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
@Entity
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class BugTicket {
@Id
@GeneratedValue
@Column(name = "id", nullable = false)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn
private TestUser testUser;
public BugTicket(TestUser testUser) {
this.testUser = testUser;
}
}
class Driver {
public void run(String... args) throws Exception {
TestUser u1 = new TestUser("user-id-1", "value1");
userRepository.save(u1);
var ticket = new BugTicket(u1);
ticketRepository.save(ticket);
ticket.getTestUser().setSomeProperty("value2");
ticketRepository.save(ticket);
}
}
我想在更新BugTicket实体时更新用户实体的'someProperty'。因此,我将CascadeType.ALL添加到BugTicket的用户。
但是,当调用保存时,hib会尝试创建一个新用户并抛出异常
Hibernate: insert into test_user (some_property, id) values (?, ?)
2022-10-02 18:33:39.404 WARN 30632 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 23505
2022-10-02 18:33:39.405 ERROR 30632 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: duplicate key value violates unique constraint "test_user_pkey"
Detail: Key (id)=(user-id-1) already exists.
为什么Hibernate会再次尝试插入用户?是从BugTicket中删除CascadeType.all,并显式保存用户的ticket。getTestUser()。setSomeProperty(“value 2”);“唯一的办法?
2条答案
按热度按时间iyr7buue1#
当你试图保存你的“ticket”时,ticket.getTestUser()被分离,因此Hibernate将尝试创建它。你需要在事务内部工作。
ktca8awb2#
当您使用jparepository保存实体时,它会返回持久化的用户,因此您需要使用它。
正如@grigouille所说,该方法应该是事务性的,因为如果没有它,当您保存BugTicket时,将尝试再次保存TestUser,因为它不是托管实体。
使方法事务像这样,它将只保存TestUser一次,并且当您稍后在方法中更新它时,它将成为托管实体,您甚至不必调用另存为Hibernate。当提交事务时,污垢检查机制将把对它的任何更改写入数据库