多线程操作Mysql问题

lee_鹿游原 2015-03-28 10:45:14
这个存储过程,多线程下会丢失数据。

CREATE DEFINER=`root`@`%` PROCEDURE `game_register1`(IN `_status` int,IN `_account` varchar(64),IN `_password` varchar(64),IN `_platform` int)
BEGIN
#Routine body goes here...
DECLARE _id BIGINT;
SET _id = -1;
SELECT userid INTO _id FROM game_user.account WHERE account=_account AND platform=_platform;
IF _id < 0 THEN
INSERT INTO game_user.account(status,account,password,platform) SELECT _status,_account,_password,_platform FROM DUAL WHERE NOT EXISTS(SELECT * FROM game_user.account WHERE account=_account AND platform=_platform);
SELECT userid INTO _id FROM game_user.account WHERE account=_account AND platform=_platform;
IF LAST_INSERT_ID() = _id then
SELECT 1,_id;
ELSE
SELECT -2;
END IF;
ELSE
SELECT -1;
END IF;
END
;;

昨天经过测试,问题出在 : INSERT INTO game_user.account(status,account,password,platform) SELECT _status,_account,_password,_platform FROM DUAL WHERE NOT EXISTS(SELECT * FROM game_user.account WHERE account=_account AND platform=_platform);
WHERE NOT EXISTS(SELECT * FROM game_user.account WHERE account=_account AND platform=_platform); 去掉这部分代码,数据不会丢失,前者数据会丢失。
不太理解为何会出现这种状况 ,希望能帮忙分析下。
...全文
308 6 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
Tiger_Zhao 2015-04-03
  • 打赏
  • 举报
回复
从数据库上是没有错的,所以只能是代码编写的逻辑和你预期不同。
lee_鹿游原 2015-04-03
  • 打赏
  • 举报
回复
引用 3 楼 Tiger_Zhao 的回复:
按你代码的逻辑这是正常的表现啊: (1)如果A、B两个会话并发,用相同的 _account、_platform 调用这个存储过程; (2)并且第一个SELECT都取得了 _id=-1 的结果,“一起”调用INSERT; (3)数据库还是会给两个INSERT操作排队的,假设A争先,插入了一条 id=10 的记录,并且通过 SELECT 1,_id 返回结果10,结束事物; (4)这下轮到B,因为已经有 id=10 的记录,被 NOT EXISTS 排出,所以实际没有插入记录,但是照样可以取到 _id=10,并且通过 SELECT 1,_id 返回结果一样是10。 这样只插入一条记录,A、B都返回同一个id。 假如去掉 NOT EXISTS,步骤(4)B会插入 id=11 的记录,返回的也是11。 两个会话会查如两条。 你到底需要哪个逻辑?
这个问题,最后我在调用存储过程 函数外,加锁了。 防止多线程同时调用存储过程... 数据保证正常。 之前是多线程调用,mysql没有报任何错误日志,而且调用这个存储过程会丢失数据,纠结其丢失原因。
Tiger_Zhao 2015-04-02
  • 打赏
  • 举报
回复
假如 LAST_INSERT_ID() 是会话直接独立的话,(4)走的应该是 SELECT -2。
Tiger_Zhao 2015-04-02
  • 打赏
  • 举报
回复
按你代码的逻辑这是正常的表现啊:
(1)如果A、B两个会话并发,用相同的 _account、_platform 调用这个存储过程;
(2)并且第一个SELECT都取得了 _id=-1 的结果,“一起”调用INSERT;
(3)数据库还是会给两个INSERT操作排队的,假设A争先,插入了一条 id=10 的记录,并且通过 SELECT 1,_id 返回结果10,结束事物;
(4)这下轮到B,因为已经有 id=10 的记录,被 NOT EXISTS 排出,所以实际没有插入记录,但是照样可以取到 _id=10,并且通过 SELECT 1,_id 返回结果一样是10。
这样只插入一条记录,A、B都返回同一个id。

假如去掉 NOT EXISTS,步骤(4)B会插入 id=11 的记录,返回的也是11。
两个会话会查如两条。

你到底需要哪个逻辑?
LongRui888 2015-04-02
  • 打赏
  • 举报
回复
是mysql的问题, WHERE NOT EXISTS(SELECT * FROM game_user.account WHERE account=_account AND platform=_platform); 这个应该是判断如果当前要插入的值,如果不存在于 game_user.account 表中,那么就插入,判断的时候根据 账户和 平台。
贫下码农 2015-04-02
  • 打赏
  • 举报
回复
你这问题到底是 mysql 还是 mssql

34,838

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧