MySQL 中等效的 Oracle 序列
Oracle sequences equivalent in MySQL
我有以下 table 类似于 Oracle user_sequences
。
我有顺序逻辑 prefix/suffix 一些东西,但为了简单起见,我在这里略过一些。
create table my_seq(
min_value integer,
Max_value integer,
last_value integer,
increment_by tinyint,
customer_id integer);
假设当前table有两条记录。
insert into my_seq(min_value,max_value,last_value,increment_by,customer_id)
values(1,99999999,1,1,'foo#',1),(1,999999999,100,1,'foo#',2);
我的 foo table 结构是这样的,
create table foo(id Auto_increment,foo_number varchar(20),customer_id integer)
;
约束:
我不能使用 MySQL AUTO_INCREMENT 列,因为 foo
包含不同的客户数据,每个客户都可以选择 foo_number
自动生成或手动输入,如果客户选择,应该会有差距auto_generation。所以 customer=1 已经选择了它,foo# 应该是 1,2,3,4 等,不允许有间隙。
到目前为止一切顺利,如果我的应用 运行 在 single thread
中,我们已经实现了自动递增逻辑。我们生成 foo_number
并填充 foo
table,以及其他数据点。
我只是做了一个查询来获取下一个 auto#。
select last_number from my_seq where customer_id=?;
读取 # 并更新记录。
update my_seq set last_number=last_number+increment_by where customer_id=?;
问题:
当多个并发会话尝试 运行 select last_number from my_seq...
时,它 returns 相同 foo_number
多次。另外,由于应用端限制和性能瓶颈,我无法在应用程序中强制执行单线程,因此需要在数据库端解决它。
请指教,如何避免重复号码?请帮助,提前致谢。
我做了 google,许多 Whosebug 链接建议 get_last_id()
,如您所见,我无法使用它。
我结合@Akina 和@RickJames 的建议解决了这个问题,感谢你们的支持。
create table my_seq(
min_value integer,
Max_value integer,
last_value integer,
increment_by tinyint,
customer_id integer)ENGINE = InnoDB;
这里ENGINE=InnoDB
很重要。
为了确保阅读时有table级锁定,我将我的应用程序代码修改为:
Auto-Commit=FALSE
然后,
//very import to begin the transaction
begin;
select last_number from my_seq where customer_id=? FOR UPDATE;
Read the result in App.
update my_seq set last_number=last_number+1 where customer_id=?;
commit;
即使在多个并发会话的情况下,这也会生成唯一的 sequence number
。
我遇到了另一个问题,这个解决方案减慢了我生成序列号的其他地方。我已经通过索引 customer_id.
解决了启用行级锁而不是 table 级锁的问题
ALTER TABLE TABLE_NAME ADD INDEX (customer_id);
希望对其他人有所帮助。
我有以下 table 类似于 Oracle user_sequences
。
我有顺序逻辑 prefix/suffix 一些东西,但为了简单起见,我在这里略过一些。
create table my_seq(
min_value integer,
Max_value integer,
last_value integer,
increment_by tinyint,
customer_id integer);
假设当前table有两条记录。
insert into my_seq(min_value,max_value,last_value,increment_by,customer_id)
values(1,99999999,1,1,'foo#',1),(1,999999999,100,1,'foo#',2);
我的 foo table 结构是这样的,
create table foo(id Auto_increment,foo_number varchar(20),customer_id integer)
;
约束:
我不能使用 MySQL AUTO_INCREMENT 列,因为 foo
包含不同的客户数据,每个客户都可以选择 foo_number
自动生成或手动输入,如果客户选择,应该会有差距auto_generation。所以 customer=1 已经选择了它,foo# 应该是 1,2,3,4 等,不允许有间隙。
到目前为止一切顺利,如果我的应用 运行 在 single thread
中,我们已经实现了自动递增逻辑。我们生成 foo_number
并填充 foo
table,以及其他数据点。
我只是做了一个查询来获取下一个 auto#。
select last_number from my_seq where customer_id=?;
读取 # 并更新记录。
update my_seq set last_number=last_number+increment_by where customer_id=?;
问题:
当多个并发会话尝试 运行 select last_number from my_seq...
时,它 returns 相同 foo_number
多次。另外,由于应用端限制和性能瓶颈,我无法在应用程序中强制执行单线程,因此需要在数据库端解决它。
请指教,如何避免重复号码?请帮助,提前致谢。
我做了 google,许多 Whosebug 链接建议 get_last_id()
,如您所见,我无法使用它。
我结合@Akina 和@RickJames 的建议解决了这个问题,感谢你们的支持。
create table my_seq(
min_value integer,
Max_value integer,
last_value integer,
increment_by tinyint,
customer_id integer)ENGINE = InnoDB;
这里ENGINE=InnoDB
很重要。
为了确保阅读时有table级锁定,我将我的应用程序代码修改为:
Auto-Commit=FALSE
然后,
//very import to begin the transaction
begin;
select last_number from my_seq where customer_id=? FOR UPDATE;
Read the result in App.
update my_seq set last_number=last_number+1 where customer_id=?;
commit;
即使在多个并发会话的情况下,这也会生成唯一的 sequence number
。
我遇到了另一个问题,这个解决方案减慢了我生成序列号的其他地方。我已经通过索引 customer_id.
解决了启用行级锁而不是 table 级锁的问题ALTER TABLE TABLE_NAME ADD INDEX (customer_id);
希望对其他人有所帮助。