You need to enable JavaScript to run this app. 调用Repository.saveAll抛出InvalidDataAccessApiUsageException异常如何解决?
优惠活动
大模型
产品
解决方案
定价
更多

调用Repository.saveAll抛出InvalidDataAccessApiUsageException异常如何解决?

异常根因

反序列化Bugzilla接口响应时,若同一个BugUser(用户ID相同)同时出现在经办人字段assigned_to_detail和抄送列表cc_detail中,Spring RestTemplate会生成两个内存地址不同、但主键ID完全一致的BugUser游离对象。JPA执行merge操作时,无法处理同一个主键对应多个游离实例的场景,因此抛出冲突异常。当你注释掉任意一个关联属性后,同一个ID的BugUser只会有一个实例,自然不会触发冲突。

解决方案

1. 修正不合理的级联配置

BugUser属于独立的主数据实体,不应该跟随Bug对象级联全量操作,删除两个关联注解中的cascade = CascadeType.ALL配置即可,调整后代码如下:

@Entity
@Table
public class Bug { // 注意Java类名规范建议用大驼峰
    // ....
    @ManyToOne (fetch = FetchType.EAGER)
    @JoinColumn (name = "assigned_to_user_id")
    @SerializedName ("assigned_to_detail")
    protected BugUser assignedTo;

    // 注意:@ManyToMany不能用@JoinColumn映射,需要用@JoinTable
    @ManyToMany
    @JoinTable(
        name = "bug_cc_rel",
        joinColumns = @JoinColumn(name = "bug_id"),
        inverseJoinColumns = @JoinColumn(name = "user_id")
    )
    @SerializedName ("cc_detail")
    protected List<BugUser> cc;
    // ...
}

2. 反序列化后统一替换相同主键的BugUser实例

拿到RestTemplate反序列化后的Bug对象后,先按主键去重所有关联的BugUser,保证同一个主键的BugUser在整个对象结构中是同一个实例:

// 按主键去重收集所有关联的BugUser
Map<Long, BugUser> userMap = new HashMap<>();
if (bug.getAssignedTo() != null) {
    userMap.put(bug.getAssignedTo().getId(), bug.getAssignedTo());
}
if (bug.getCc() != null) {
    bug.getCc().forEach(ccUser -> userMap.putIfAbsent(ccUser.getId(), ccUser));
    // 替换抄送列表的实例为统一实例
    bug.setCc(bug.getCc().stream()
        .map(u -> userMap.get(u.getId()))
        .collect(Collectors.toList()));
}
// 替换经办人实例为统一实例
if (bug.getAssignedTo() != null) {
    bug.setAssignedTo(userMap.get(bug.getAssignedTo().getId()));
}

3. 持久化前先处理BugUser为托管态

如果需要同步更新用户信息,可先将去重后的BugUser批量持久化,拿到托管态实例后再赋值回Bug对象,最后持久化Bug即可:

// 先批量持久化所有去重后的用户
List<BugUser> savedUsers = bugUserRepository.saveAll(userMap.values());
Map<Long, BugUser> savedUserMap = savedUsers.stream()
    .collect(Collectors.toMap(BugUser::getId, Function.identity()));

// 替换Bug中的用户引用为托管态实例
bug.setAssignedTo(savedUserMap.get(bug.getAssignedTo().getId()));
bug.setCc(bug.getCc().stream()
    .map(u -> savedUserMap.get(u.getId()))
    .collect(Collectors.toList()));

// 最后持久化Bug
bugRepository.save(bug);

内容的提问来源于stack exchange,提问作者TheQuestionIs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 05:06:06