Mysql 如何在Hibernate中为每个公司创建customerNumber生成器

Mysql 如何在Hibernate中为每个公司创建customerNumber生成器,mysql,hibernate,jpa,orm,hibernate-mapping,Mysql,Hibernate,Jpa,Orm,Hibernate Mapping,我有一个客户表,每个客户都属于一家公司,公司希望他们的客户号从0开始,并在添加客户时递增,当companyB添加客户时,companyA的客户号不应受到影响。CustomerId内部可以是任意数字,customerNumber必须在公司ID的上下文中递增,无间隙我的意思是0,1,2,3,4,如果2被删除,它就消失了,下一次插入应该是5,而不是2 Example: companyId customerNumber customerId 0 0

我有一个客户表,每个客户都属于一家公司,公司希望他们的客户号从0开始,并在添加客户时递增,当companyB添加客户时,companyA的客户号不应受到影响。CustomerId内部可以是任意数字,customerNumber必须在公司ID的上下文中递增,无间隙我的意思是0,1,2,3,4,如果2被删除,它就消失了,下一次插入应该是5,而不是2

Example: 
    companyId customerNumber  customerId 
    0         0               0
    0         1               1
    0         2               2
    0         3               3
    0         4               4
    0         5               5
    1         0               6
    1         1               7
    1         2               8
我想知道是否有比打开一个事务、查找max customerNumber、使用max+1作为customerNumber插入一个条目并关闭事务更好的方法

是否可以使用某种注释来指定生成customerNumber的条件?下一个customerNumber应该是该公司内可用的最高编号。我还有大约20个其他实体,它们具有类似的基于日期和comapnyId的人类可读增量id要求,我想让customerNumber类型字段的生成尽可能简单,我不想每次保存一个新实体时都记得这样做

比如:

@SequenceGenerator(uniqueOver="companyId,customerNumber",strategy=GenerationType.AUTO)
private Long customerNumber;
该解决方案应该符合ACID,因为我正在处理股票和财务数据

更新:我已经将id重命名为customerId,将customerId重命名为customerNumber以防止混淆

更新: 当我指的是无缺口时,我的意思是客户编号应该是0,1,2,3,4,5,6,7,8,9-如果我删除编号4,它将永远消失,下一次插入应该是10,除非我创建一个新公司,那么他们的第一个客户应该从0开始

更新: 我将spring与hibernate结合使用,因此@PrePersist注释对我不起作用。如果建议使用@PrePersist作为解决方案,那么它需要在spring下工作,因此需要回答Simon的问题:

我不确定的建议答案:


虽然我无法与hibernate对话,但很抱歉,您可以通过mysql中的一个表来实现这一点,只要它使用myisam引擎,表结构如下:

create table ai_test (
    company_id integer,
    customer_number integer auto_increment,
    primary key (company_id, customer_number)
) engine=MyISAM;
这里有一把小提琴,显示了它的作用:

很抱歉,我无法为您将此转换为hibernate-从未使用过它,但这可能是一个起点

编辑 由于inno是必需的,您可以使用此表和触发器:

create table ai_test (
    company_id integer,
    customer_number integer,
    primary key (company_id, customer_number)
) engine=InnoDB;


create trigger inno_composite_ai_ok before insert on ai_test
for each row 
begin
    set new.customer_number =     
        (select ifnull((select max(customer_number)+1 
                         from ai_test 
                           where 
                        company_id=new.company_id),1));
end//
这里有一把小提琴样品供您使用:

编辑 再更新一次,包括单列PK的要求

create table ai_test (
    company_id integer,
    customer_no integer,
    customer_id integer primary key auto_increment

) engine=InnoDB;

create trigger inno_composite_ai_ok before insert on ai_test
for each row 
begin
    set new.customer_no =     
        (select ifnull((select max(customer_no)+1 
                         from ai_test 
                           where 
                        company_id=new.company_id),1));
end//
注意:如果您使用hibernate,您可以而且可能应该在公司/客户号上设置一个唯一的约束; 示例查询

Query Query=session.createquery插入客户公司标识,客户标识+选择:公司标识,IFNULLmaxcustomer标识,1+1 from customer,其中公司标识=:公司标识

    //set the company_id here

    int result = query.executeUpdate();
注意:IFNULL是一种特定于MYSQL的语法


我建议将company id auto_increment字段保留在一个单独的company master表中。

您正在寻找序列号生成,而无需编写ddl来为每个表生成新的序列号。使用单独的序号表执行此操作,并创建一个select for update事务以锁定两个表以进行插入。Hibernate通过增强的表来实现这一点

这里有一个很好的例子:

向下滚动到TABLESEQUENCE部分,这是一个序列号表

在本例中,只需将客户名称指定为序列名称,即可获得正确的序列


开销是为每个新公司生成一个序列行,并为每个新客户锁定表。

您的TableSequenceIdentifier类,在我的例子中,我假设它是customer类?如何使用表序列示例获取每个公司的客户编号?表序列标识符类是一个单独的表,它只存储客户的序列值。它将保存公司ID和该公司的下一个序列值。Hibernate提供了增强的表来执行select for update/update策略来包装插入事务。这将为您提供一个锁安全序列更新。您的客户表插入现在将依赖于表序列标识符类。我不太明白。。。我已经更新了我的问题,customerId是一个自动递增的字段,每个公司可以有多个客户,每个公司的customerNumber应该递增。我的CustomerNumberSequenceIdentifier类对于我尝试执行的操作是否正确,以及如何将其引入CustomerNumber中,以便根据上面的示例获得每家公司递增的客户编号?我发现的例子都只是展示了序列号表是如何生成序列的。请随意编辑我问题中的hibernate模型并填补空白。
    //set the company_id here

    int result = query.executeUpdate();