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

JPA(EclipseLink)如何实现按COMPANY_NR分组自增DELIVERY_NR主键

解决方案

JPA 标准的 @GeneratedValue 序列生成策略本身不支持按其他字段分组生成独立序列,你可以通过以下两种适配 EclipseLink 的方案实现需求:


前置错误修正

你当前代码里的 @IdClass(value = Delivery.class) 配置不符合 JPA 规范,复合主键对应的主键类必须是独立的可序列化类,不能是实体类本身,先修正该配置:

// 独立复合主键类
public class DeliveryId implements Serializable {
    private String deliveryNr;
    private String companyNr;

    // 必须提供无参构造、全参构造
    // 必须重写equals()和hashCode()方法
}

实体类上修改为 @IdClass(DeliveryId.class)


方案一:业务层生成主键(实现简单、兼容性好)

去掉 deliveryNr 字段上的 @GeneratedValue 和 @SequenceGenerator 注解,在保存 Delivery 实体的业务逻辑前,先查询对应 companyNr 下的最大 deliveryNr,加1后赋值再保存:

// 业务层保存逻辑示例
@Transactional
public Delivery saveDelivery(Delivery delivery) {
    // 加悲观写锁避免并发场景下生成重复ID
    TypedQuery<Integer> maxQuery = em.createQuery(
        "SELECT COALESCE(MAX(CAST(d.deliveryNr AS integer)), 0) + 1 FROM Delivery d WHERE d.companyNr = :companyNr",
        Integer.class
    );
    maxQuery.setParameter("companyNr", delivery.getCompanyNr());
    maxQuery.setLockMode(LockModeType.PESSIMISTIC_WRITE);
    Integer nextNr = maxQuery.getSingleResult();
    delivery.setDeliveryNr(String.valueOf(nextNr));
    return em.merge(delivery);
}

  1. 自定义序列生成类,实现 EclipseLink 的 Sequence 接口,逻辑为按传入的 companyNr 生成对应分组的自增ID
  2. 在实体类上通过 @GeneratedValue 指定自定义生成器:
// 自定义序列生成器
public class GroupedSequence extends Sequence {
    @Override
    public Object getGeneratedValue(Accessor accessor, WriteObjectQuery writeQuery) throws DatabaseException {
        Delivery entity = (Delivery) writeQuery.getObject();
        String companyNr = entity.getCompanyNr();
        // 此处逻辑和方案一的查询逻辑一致,查询对应companyNr的最大deliveryNr加1
        // 省略重复的查询代码,最终返回生成的deliveryNr
    }

    // 其他必须实现的方法可按需返回默认值
}

实体类配置修改:

@Id
@GeneratedValue(generator = "grouped-delivery-generator")
@org.eclipse.persistence.annotations.SequenceGenerator(
    name = "grouped-delivery-generator",
    sequenceName = "dummy", // 无实际作用,占位即可
    sequenceClass = GroupedSequence.class
)
@Column(name = "DELIVERY_NR", nullable = false)
private String deliveryNr;

高并发场景优化

如果业务并发量很高,可以额外创建一张序列维护表 COMPANY_DELIVERY_SEQ(COMPANY_NR, CURRENT_MAX_NR),每次生成ID时原子更新该表的 CURRENT_MAX_NR 字段,避免每次查询主表的最大值,提升性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 03:57:02