【问题标题】:Multi-Tenant Sequence generator in HibernateHibernate 中的多租户序列生成器
【发布时间】:2021-06-20 07:03:55
【问题描述】:

我有一个以 orgId 和 clientId 作为复合键的 Client 实体。当我必须插入一个新的客户端对象时,我必须为每个 orgId 依次生成 clientId id,为此,我通过在单独的表中维护每个 orgId 的最后一个 clientId 并选择、添加 1 和更新它。

@Entity
@Table(name = "ftb_client")
public class Client implements Serializable {

    @Id
    @JoinColumn(name = "ORG_ID")
    protected String orgId;

    @Id
    @Column(name = "CLIENT_ID")
    protected int clientId;

    @Column(name = "CLIENT_NAME_ENG")
    private String clientNameEng;
//....
}

@Entity
@Table
public class MySeq implements Serializable {
    @Id
    protected String orgId;

    private int lastClientId;
//....
}

public Long getNewClientId(String orgId) {
    MySeq mySeq = getSession()
            .createQuery("from MySeq where orgId = :orgId", MySeq.class)
            .setParameter("orgId", orgId)
            .setLockMode(LockModeType.PESSIMISTIC_WRITE)
            .uniqueResult();

    mySeq.setLastClientId(mySeq.getLastClientId() + 1);

    return mySeq.getLastClientId();
}

但是,如果有数千个并发请求,这会导致重复的 id 生成。因此,为了使其线程安全,我必须使用悲观锁定,以便多个请求不会生成相同的 clientId。但是现在的问题是,直到事务结束并且并发请求保持等待很长时间,锁才会被释放。

因此,如果我可以为每个 orgId 使用单独的序列,而不是使用锁,那么我也可以使 id 生成并发。我想通过执行诸如client_sequence_[orgId]之类的操作来确定运行时中的序列名称并执行它来生成id,从而手动执行序列生成器。

而且我还想让它独立于数据库,或者至少对于 Oracle、MySQL 和 Postgres。

我想知道是否有可能或有其他方法吗?

【问题讨论】:

    标签: java multithreading hibernate hql


    【解决方案1】:

    不管你是否使用PESSIMISTIC_WRITE,如果你更新实体,无论如何都会获得一个锁。不同之处在于,在您在此处描述的情况下,会急切地获取锁,从而防止丢失写入。

    通常,这可以通过为序列增量创建单独的事务来解决。为了提高性能,您应该增加一个批处理因子,即 10,并将 10 个值保留在内存队列中以供服务。当队列为空时,您要求另外 10 个值等。

    Hibernate 使用 org.hibernate.id.enhanced.TableGeneratororg.hibernate.id.enhanced.PooledOptimizer 在幕后实现这一点。因此,如果您事先知道所需的序列,我建议您为此目的使用这些工具。如果你愿意,你也可以自己做类似的事情。

    【讨论】:

      猜你喜欢
      • 2014-11-25
      • 1970-01-01
      • 2014-02-07
      • 1970-01-01
      • 2022-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-23
      相关资源
      最近更新 更多