You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在@JoinTable中使用@Version实现乐观锁?

JPA 3.1下@ManyToMany关联表实现乐观锁的方案

现状:JPA 3.1不支持直接通过@JoinTable实现中间表乐观锁

原生JPA规范中,@JoinTable对应的关联表被视为纯关联结构,JPA不会为其生成对应的实体类,而@Version注解只能作用于实体类的字段上,因此无法直接通过主实体的注解为中间表的version字段启用乐观锁。

可行的替代方案:拆分关联为带实体的双向关联

虽然你希望避免创建关联实体,但这是目前JPA规范内唯一能实现中间表乐观锁的方式——将@ManyToMany拆分为两个@OneToMany,创建专门的关联实体映射中间表,并在该实体中添加@Version字段:

1. 创建关联实体与复合主键类

关联实体映射中间表,包含联合主键和版本字段:

@Entity
@Table(name = "company_relationship")
@IdClass(CompanyRelationshipId.class)
public class CompanyRelationship {
    @Id
    @Column(name = "company_id")
    private Long companyId;

    @Id
    @Column(name = "relationship_id")
    private Long relationshipId;

    @Version
    private Integer version;

    // 关联到主实体和 lookup 实体
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", insertable = false, updatable = false)
    private Company company;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "relationship_id", insertable = false, updatable = false)
    private CompanyRelationshipLookup relationshipLookup;

    // getter、setter、构造方法
}

复合主键类(需实现Serializable并重写equals/hashCode):

public class CompanyRelationshipId implements Serializable {
    private Long companyId;
    private Long relationshipId;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CompanyRelationshipId that = (CompanyRelationshipId) o;
        return Objects.equals(companyId, that.companyId) && Objects.equals(relationshipId, that.relationshipId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(companyId, relationshipId);
    }

    // getter、setter
}

2. 修改主实体的关联注解

将原有的@ManyToMany替换为@OneToMany关联到新创建的实体:

@Audited(targetAuditMode = NOT_AUDITED)
@OneToMany(mappedBy = "company", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
private Set<CompanyRelationship> companyRelationships = new HashSet<>();

通过这种方式,你可以利用关联实体的@Version字段实现中间表的乐观锁逻辑,同时保留对关联关系的管理能力。

关于未来版本的支持

截至目前,JPA后续版本(包括规划中的JPA 4.0)没有公开计划为@JoinTable添加支持中间表额外字段(如@Version)的功能。JPA的@ManyToMany设计初衷是用于无额外属性的纯关联场景,带有额外字段的关联场景,官方始终推荐使用关联实体的方式实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:47:42