我有以下表格类似于Oracleuser_sequences
。
我有序列前缀/后缀的逻辑,但为简单起见,我在这里跳过了不那么重要的事情。
create table my_seq(
min_value integer,
Max_value integer,
last_value integer,
increment_by tinyint,
customer_id integer);
假设当前表中有两条记录。
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 表结构是这样的,
create table foo(id Auto_increment,foo_number varchar(20),customer_id integer)
;
受限:我不能使用MySQL AUTO_INCREMENT列,因为foo
包含不同的客户数据,每个客户都可以选择自动生成或手动输入foo_number
如果客户选择auto_generation,应该会有差距。所以客户=1选择了它,foo#应该是1,2,3,4等,不允许有间隙。
到目前为止一切顺利,如果我的应用程序在single thread
中运行,我们已经实现了自动增量逻辑。我们生成foo_number
并填充foo
表中,以及其他数据点。
我只是做一个查询来获取下一个自动#。
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...
时,它会多次返回相同的foo_number
。此外,由于应用程序端限制和性能瓶颈,我无法在应用程序中强制执行单线程,因此需要在数据库端解决它。
请建议,我如何避免重复的数字?请帮忙,提前谢谢。
我做了谷歌,许多堆栈溢出链接建议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
非常重要。 为了确保在阅读时有表级锁定,我将我的应用程序代码修改为:
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启用行级锁而不是表级锁。
ALTER TABLE TABLE_NAME ADD INDEX (customer_id);
希望这对其他人有帮助。