多线程调用生成主键流水号存储过程产生主键冲突问题解决方案
遇到开发多线程测试插入数据的时候发现主键冲突问题
问题具体描述如下:
--------------------------------------------------------------
调用Procedure_insert
Procedure_insert
Begin
Call procedure(获取流水号)
Insert into table values(流水号作为id,其他列);
End
流水号存储过程:
Update 统计表 统计字段+1
Update 统计表 最终流水号 set类型+年月日+补零位+统计字段
Select 最终流水号; //作为主键
---------------------------------------------------------------
问题:多线程并发会生成的主键冲突
写个java多线程调用一下测试,发现当加上事务便不会出现问题,无论在存储过程加还是代码过程加事务都可以,看似问题就这么解决了,方案如下:
-----------------------------------------------------------------
程序代码 con.begin 开始事务
调用Procedure_insert
Procedure_insert
Begin
Call procedure(获取流水号)
Insert into table values(流水号作为id,其他列);
End
程序代码 con.commit();
流水号存储过程:
Update 统计表 统计字段+1
Update 统计表 最终流水号 set类型+年月日+补零位+统计字段
Select 最终流水号; //作为主键
-----------------------------------------------------------------
不过问题究竟发生在哪里,既然是主键冲突,并且只有在多线程并发下,没有事务的情况下才会发生,那么单独测试一下生成主键的存储过程,如下:
发现问题了,果然是多线程下没加事务造成的
既然测试出来结果,也知道了解决方法,貌似就解决了,那么又有新的问题了,为什么不加事务多线程调用生成流水号的存储过程会产生相同的主键呢?
和我的流水号生成方式有关
procedure
begin
update 语句;
update 语句 拼接;
select 语句;
end
由于多线程并发,导致更新流水号时是异步的,第一个语句可能同时执行了,然后再执行第二句,导致最终只会产生最后一个主键;总之生成主键的过程并不是一个整体,导致了生成同一个主键。