Spring Boot在外部事务提交时执行与内部(REQUIRED_NEW)事务相同的插入


@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)
}

相关内容

  • 没有找到相关文章

最新更新