为了账号安全,请及时绑定邮箱和手机立即绑定

mysql 存储过程多次插入只有一次成功,请问这是什么原因?

mysql 存储过程多次插入只有一次成功,请问这是什么原因?

噜噜哒 2019-05-21 10:10:13
今天碰到一个奇葩的问题,同样的批量插入,一个可以批量插入成功,一个却不能插入成功,请大家看看。以下是伪代码--存储过程A(负责插入SQL)(有参数,这里就不写了,主要用于组装SQL并执行)CREATEPROCEDURE`A`()BEGINREPLACEINTO`table`(`num`)SELECTSUM(`num`)AS`num`FROM`table`;END;--存储过程B(负责循环处理参数,传递给A)CREATEPROCEDURE`B`()BEGINWHILE100DOCALL`A`;ENDWHILE;END;上面的两个存储过程就是我的代码逻辑,每次REPLACEINTO...SELECT...大概需要0.2秒的时间。当我调用CALL`B`的时候,只能第一条插入成功,其他的均无插入,也没有报错。生成的SQL语句是无错误的,因为打印的语句可以手动批量插入。更奇葩的是,,我有一个同样的功能的其他REPLACEINTO...SELECT...(相对执行时间短,0.01秒级),却可以批量插入成功。这个是不是锁导致的呢,我用的InnoDB存储引擎。可能有些情况我说的不太明白:上面的代码是伪代码,循环结构和生成执行SQL均无问题这里主要讨论三个问题:是不是行锁导致的(按说不应该)同样的表,同样的查询结构,为何执行时间短的可以插入(0.001级别),执行时间长的不能插入(0.1级别)执行过程中调用执行过程,是同步执行还是异步执行(即是否等CALL执行完毕后在走流程,还是不等执行完毕,就走下一个循环流程)
查看完整描述

2 回答

?
慕无忌1623718

TA贡献1744条经验 获得超4个赞

我想到了一个原因,正在测试,如果CALL是异步调用,而我SQL执行是这样的:
SET@sql=$sql;
PREPARESTMTFROM@sql;
EXECUTESTMT;
DEALLOCATEPREPARESTMT;
@sql会相互覆盖。看看测试结论吧。
现在代码是这样的:
CREATEPROCEDURE`A`()
BEGIN
SET$sql='REPLACEINTO`table`(`num`)
SELECTSUM(`num`)AS`num`
FROM`table`;';
SET@sql=$sql;
PREPARESTMTFROM@sql;
EXECUTESTMT;
DEALLOCATEPREPARESTMT;
END;
CREATEPROCEDURE`B`()
BEGIN
WHILE100DO
CALL`A`;
ENDWHILE;
END;
                            
查看完整回答
反对 回复 2019-05-21
?
泛舟湖上清波郎朗

TA贡献1818条经验 获得超3个赞

你没有说明表的主键和唯一键,猜测id是主键,但replaceinto代入的id始终是0,所以最终数据库里只能有一条记录,如果id是自增长的,试试设成null,或改用insertinto,而不是replaceinto.
EDITED
我试了下,按你给的存储过程会陷入死循环,因为while100一直为真.
可以试试改成这样:
delimiter$$
CREATEPROCEDURE`A`()
BEGIN
REPLACEINTO`sumtable`(`id`,`mysum`)
SELECT0AS`id`,SUM(`mysum`)AS`mysum`
FROM`sumtable`;
END;
$$
--存储过程B(负责循环处理参数,传递给A)
CREATEPROCEDURE`B`()
BEGIN
DECLAREv1INTDEFAULT100;
WHILEv1>0DO
CALL`A`;
SETv1=v1-1;
ENDWHILE;
END;
$$
运行
callB()
会得到100条记录.
                            
查看完整回答
反对 回复 2019-05-21
  • 2 回答
  • 0 关注
  • 889 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信