java - 当外部事务提交时,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)
}
}
我有从数据库加载用户的外部事务。然后将用户拆分为多个部分,并在新的(Requires_new)内部事务中进行处理。在每个用户的内部事务期间,我创建配置文件实体然后保存这些用户。当内部事务结束时,它会为新的配置文件执行提交和 sql 插入,并为现有用户执行更新。但是当外部事务结束并执行提交时,它会执行相同的插入和更新,并且我得到唯一的主键违规。
日志:
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)
}
推荐阅读
- scala - 用于 Finatra Web 服务器的具有 Kerberos 身份验证的 HTTP/Spnego
- ios - 如何将 UIButtons 添加到我的 TableViewCell?
- mysql - 当数据库中的数据更新时,如何在前端更新检索到的数据?
- gdb - 如何将 GDB 格式的半字内存设为十六进制?
- javascript - 复制和粘贴自定义 FabricJS 对象
- ios - 当我从视图返回标签栏控制器时,标签栏不显示
- elm - 访问以前陡峭的 Html
- ruby-on-rails - Ruby 版本 2.3.3 Gemfile 2.3.0(Sprockets 更新)
- javascript - 如何在 React 中使用 Axios 发送 JSON 对象
- python - 无法弄清楚如何将输入存储到字典