如何在 Hibernate 中为每个公司创建一个 customerNumber 生成器
How to create a customerNumber generator for each company in Hibernate
我有 table 个客户,每个客户都属于一个公司,公司希望他们的客户编号从 0 开始,并随着他们添加客户而递增,当公司 B 添加客户时,公司 A 的客户编号应该'不受影响。 CustomerId 内部可以是任何数字,customerNumber 必须在 companyId 的上下文中无间隙递增(无间隙我的意思是 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
我想知道是否有比打开交易、找到最大客户编号、使用最大+1 作为客户编号插入条目并关闭交易更好的方法
是否可以使用某种注释来指定生成 customerNumber 的条件?下一个 customerNumber 应该是该公司内可用的最大号码。 (我有大约 20 个其他实体基于日期和 comapnyId 具有类似的人类可读增量 ID 要求,我想让 customerNumber 类型的字段生成尽可能简单,我不想记住每次我坚持一个新实体时都这样做)
类似于:
@SequenceGenerator(uniqueOver="companyId,customerNumber",strategy=GenerationType.AUTO)
private Long customerNumber;
该解决方案应该符合 ACID 标准,因为我正在处理股票和财务数据。
更新:我已将 id 重命名为 customerId,将 customerId 重命名为 customerNumber 以防止混淆。
更新:
当我的意思是无间隙时,我的意思是 customerNumbers 应该是 0,1,2,3,4,5,6,7,8,9 - 如果我删除数字 4,它就永远消失了,下一个插入应该是 10,除非我创建了一个新公司,那么他们的第一个客户应该从0开始。
更新:
我在休眠中使用 spring,所以 @PrePersist 注释对我不起作用。如果建议将@PrePersist 作为解决方案,则它需要在 spring 下工作,因此需要回答 Simon 的问题:Enable @PrePersist and @PreUpdate in Spring
我不确定的建议答案:
@Entity
@Table(name = "Customer")
public class Customer {
@Table(name = "CustomerNumber")
@Entity(name = "sequenceIdentifier")
public static class CustomerNumberSequenceIdentifier {
@Id
@GenericGenerator(name = "sequence", strategy = "sequence", parameters = {
@org.hibernate.annotations.Parameter(name = "sequenceName", value = "sequence"),
@org.hibernate.annotations.Parameter(name = "allocationSize", value = "1"),
})
@GeneratedValue(generator = "sequence", strategy=GenerationType.SEQUENCE)
private Long id;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long customerId;
@ManyToOne
private Company company;
@GeneratedValue(generator = "sequenceIdentifier", strategy=GenerationType.TABLE)
private Long customerNumber
}
虽然我无法谈论休眠方面的事情(抱歉),但只要它使用 myisam 引擎,您就可以使用 mysql 中的 table 来完成此操作,使用以下命令table结构:
create table ai_test (
company_id integer,
customer_number integer auto_increment,
primary key (company_id, customer_number)
) engine=MyISAM;
这是一个 fiddle 显示实际情况:http://sqlfiddle.com/#!9/45e78/1
抱歉,我无法为您将其转换为休眠模式 - 从未使用过,但这可能是一个起点。
编辑
由于需要 inno,您可以使用此 table 和触发器:
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//
这里有一个示例 fiddle:
http://sqlfiddle.com/#!9/fffd0/14
编辑
另一项更新以包含单列 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//
请注意,您可以(并且可能应该)在 company_d/customer_no
中设置唯一约束
如果您使用休眠;
示例查询
查询 query = session.createQuery("insert into customer (company_id, customer_id)" +"(select :company_id, IFNULL(max(customer_id),1)+1 from customer where company_id = :company_id)");</p>
<pre><code> //set the company_id here
int result = query.executeUpdate();
注意:IFNULL 是 MYSQL 特定语法
我建议将公司 ID auto_increment
字段保存在单独的公司主文件中 table。
您正在寻找一个序列号生成器,而无需编写 ddl 来为每个 table 生成一个新的序列号。使用单独的序列号 table 执行此操作并创建一个 select 用于更新事务以锁定两个 table 用于插入。 Hibernate 使用 enhanced-tables.
来做到这一点
这是一个很好的例子:
http://vladmihalcea.com/hibernate-identity-sequence-and-table-sequence-generator/
向下滚动到 TABLE(SEQUENCE) 部分,这是一个 table 序列号解决方案。
在示例中,只需将客户名称指定为序列名称即可获得正确的序列。
开销是为每个新公司生成一个序列行,并为每个新客户锁定 table。
我有 table 个客户,每个客户都属于一个公司,公司希望他们的客户编号从 0 开始,并随着他们添加客户而递增,当公司 B 添加客户时,公司 A 的客户编号应该'不受影响。 CustomerId 内部可以是任何数字,customerNumber 必须在 companyId 的上下文中无间隙递增(无间隙我的意思是 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
我想知道是否有比打开交易、找到最大客户编号、使用最大+1 作为客户编号插入条目并关闭交易更好的方法
是否可以使用某种注释来指定生成 customerNumber 的条件?下一个 customerNumber 应该是该公司内可用的最大号码。 (我有大约 20 个其他实体基于日期和 comapnyId 具有类似的人类可读增量 ID 要求,我想让 customerNumber 类型的字段生成尽可能简单,我不想记住每次我坚持一个新实体时都这样做)
类似于:
@SequenceGenerator(uniqueOver="companyId,customerNumber",strategy=GenerationType.AUTO)
private Long customerNumber;
该解决方案应该符合 ACID 标准,因为我正在处理股票和财务数据。
更新:我已将 id 重命名为 customerId,将 customerId 重命名为 customerNumber 以防止混淆。
更新: 当我的意思是无间隙时,我的意思是 customerNumbers 应该是 0,1,2,3,4,5,6,7,8,9 - 如果我删除数字 4,它就永远消失了,下一个插入应该是 10,除非我创建了一个新公司,那么他们的第一个客户应该从0开始。
更新: 我在休眠中使用 spring,所以 @PrePersist 注释对我不起作用。如果建议将@PrePersist 作为解决方案,则它需要在 spring 下工作,因此需要回答 Simon 的问题:Enable @PrePersist and @PreUpdate in Spring
我不确定的建议答案:
@Entity
@Table(name = "Customer")
public class Customer {
@Table(name = "CustomerNumber")
@Entity(name = "sequenceIdentifier")
public static class CustomerNumberSequenceIdentifier {
@Id
@GenericGenerator(name = "sequence", strategy = "sequence", parameters = {
@org.hibernate.annotations.Parameter(name = "sequenceName", value = "sequence"),
@org.hibernate.annotations.Parameter(name = "allocationSize", value = "1"),
})
@GeneratedValue(generator = "sequence", strategy=GenerationType.SEQUENCE)
private Long id;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long customerId;
@ManyToOne
private Company company;
@GeneratedValue(generator = "sequenceIdentifier", strategy=GenerationType.TABLE)
private Long customerNumber
}
虽然我无法谈论休眠方面的事情(抱歉),但只要它使用 myisam 引擎,您就可以使用 mysql 中的 table 来完成此操作,使用以下命令table结构:
create table ai_test (
company_id integer,
customer_number integer auto_increment,
primary key (company_id, customer_number)
) engine=MyISAM;
这是一个 fiddle 显示实际情况:http://sqlfiddle.com/#!9/45e78/1
抱歉,我无法为您将其转换为休眠模式 - 从未使用过,但这可能是一个起点。
编辑
由于需要 inno,您可以使用此 table 和触发器:
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//
这里有一个示例 fiddle: http://sqlfiddle.com/#!9/fffd0/14
编辑
另一项更新以包含单列 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//
请注意,您可以(并且可能应该)在 company_d/customer_no
中设置唯一约束如果您使用休眠; 示例查询
查询 query = session.createQuery("insert into customer (company_id, customer_id)" +"(select :company_id, IFNULL(max(customer_id),1)+1 from customer where company_id = :company_id)");</p>
<pre><code> //set the company_id here
int result = query.executeUpdate();
注意:IFNULL 是 MYSQL 特定语法
我建议将公司 ID auto_increment
字段保存在单独的公司主文件中 table。
您正在寻找一个序列号生成器,而无需编写 ddl 来为每个 table 生成一个新的序列号。使用单独的序列号 table 执行此操作并创建一个 select 用于更新事务以锁定两个 table 用于插入。 Hibernate 使用 enhanced-tables.
来做到这一点这是一个很好的例子: http://vladmihalcea.com/hibernate-identity-sequence-and-table-sequence-generator/
向下滚动到 TABLE(SEQUENCE) 部分,这是一个 table 序列号解决方案。
在示例中,只需将客户名称指定为序列名称即可获得正确的序列。
开销是为每个新公司生成一个序列行,并为每个新客户锁定 table。