@Entity
public class User {
@Id
private Long id;
@OneToOne(mappedBy = "user", cascade = {CascadeType.MERGE,CascadeType.PERSIST}, fetch = FetchType.LAZY)
private Profile profile;
}
@Entity
public class Profile {
@Id
@Column(name = "user_id")
private Long id;
@OneToOne
@MapsId
@JoinColumn(name = "user_id")
private User user;
}
public class ProcessUsers {
@Transactional
public void processUsers() {
List<Users> users = repo.getUsers();
processPart.processPart(users.getPart())
}
}
public class ProcessPart {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void processPart(List<User> users) {
users.forEach(user -> user.setProfile(new Profile(user))
repo.saveAll(users)
}
}
我有外部事务,从数据库加载用户。然后,用户被分成几个部分,并在new (Requires_new)内部事务中进行处理。在这个内部事务中,我为每个用户创建配置文件实体,然后保存这些用户。当内部事务结束时,它为新的配置文件执行提交和sql插入,并为已经存在的用户执行更新。但是当外部事务结束并执行commit时,它会进行相同的插入和更新,并且会出现唯一主键冲突。
日志:
JpaTransactionManager : Initiating transaction commit
JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(48420828<open>)]
org.hibernate.SQL : insert into profile (user_id, another_field) values (?, ?)
org.hibernate.SQL : update user set updated_field = ? where id=?
JpaTransactionManager : Closing JPA EntityManager [SessionImpl(48420828<open>)] after transaction
JpaTransactionManager : Resuming suspended transaction after completion of inner transaction
JpaTransactionManager : Initiating transaction commit
JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(713565825<open>)]
org.hibernate.SQL : insert into profile (user_id, another_field) values (?, ?)
SqlExceptionHelper : SQL Error: 23505, SQLState: 23505
SqlExceptionHelper : Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.PROFILE(USER_ID)
我猜这是因为会话是不同的(SessionImpl(48420828), SessionImpl(713565825))。
如何防止外部事务重复sql查询?
如果我没有弄错,这是一个双向关系,你还需要将用户设置为Profile
:
for (User user: users) {
Profile profile = new Profile()
profile.setUser(user)
user.setProfile(profile)
}