我有一个基本上看起来像这样的存储过程:
do_insert (IN in_x varchar(64), IN in_y varchar(64))
BEGIN
declare v_x int(20) unsigned default -1;
declare v_y int(20) unsigned default -1;
select x into v_x from xs where x_col = in_x;
if v_x = 0
then
insert into xs (x_col) values(in_x);
select x into v_x from xs where x_col = in_x;
end if;
select y into v_y from ys where y_col = in_y;
if v_y = 0
then
insert into ys (y_col) values(in_y);
select y into v_y from ys where y_col = in_y;
end if;
insert ignore into unique_table (xId, yId) values(v_x, v_y);
END
基本上我看看我是否已经在各自的表中定义了varchars,如果是,我选择了id。如果没有,那么我创建它们并获取它们的ID。然后我将它们插入unique_table
忽略它们是否已经存在。 (是的,我可能会在那里放更多的逻辑而不必进行最后的插入,但这不应该是一个问题并且KISS。)
我遇到的问题是,当我使用Google Cloud SQL在批处理JDBC语句中运行它时,我会在我的xs
表中插入重复的条目。下次运行此存储过程时,我得到以下异常:
java.sql.SQLException: Result consisted of more than one row Query: call do_insert(:x, :y)
所以我认为正在发生的是在同一个批处理语句中发生了两个具有相同in_x
值的调用。这两个调用是并行运行的,两个选择都返回0,因为它是一个新条目,然后它们都进行插入。然后下一次运行失败。
问题:
LOCK TABLE
中以防止这种情况发生吗?答案 0 :(得分:0)
我还没有测试过这个,但我猜测批处理语句引入了一定程度的并行性。所以'select x into v_x'语句可以与'insert into vx'语句竞争,允许后者执行多次。
尝试将'insert into xs'语句更改为'insert ignore'并在列上添加唯一索引。