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