最新消息:

Mysql 高并发加锁处理

Mysql 178浏览 0评论

1、背景需求:

给表里插入数据时,判断user表有无username为‘wecot’的数据,无则插入,有则提示“数据已存在”,目的就是想只插入一条username为‘wecot’的记录,并且保证其唯一性。

2、通常实现方式:

$conn = mysqli_connect('127.0.0.1', 'root', 'root') or die(mysqli_error());
mysqli_select_db($conn, 'wecot');
 
$res = mysqli_query($conn, 'SELECT count(*) as total FROM user WHERE username = "wecot" ');
$row = mysqli_fetch_array($res);
if($row['total']>0){
    exit('data exist');
}
 
mysqli_query($conn, "insert into user(username) values ('wecot')");
var_dump('error:'.mysqli_errno($conn));
$insert_id = mysqli_insert_id($conn);
 
echo 'insert_id:'.$insert_id.'<br>';
 
mysqli_free_result($res);
mysqli_close($conn);

3、问题所在:

    以上做法在一般少量请求情况,程序逻辑不会有问题。但是一旦高并发请求执行的话,程序并没有按预期执行,由于数据库会出现脏读的情况,可能会插入多条username为‘wecot’的记录。

4、解决方案:

    利用 Mysql的FOR UPDATE 语句和事务的隔离性。注意的是FOR UPDATE仅适用于InnoDB,且必须在事务(BEGIN/COMMIT)中才能生效。

    优化后代码:

$conn = mysqli_connect('127.0.0.1', 'root', 'root') or die(mysqli_error());
 
mysqli_select_db($conn, 'wecot');
mysqli_query($conn, 'BEGIN');
$res = mysqli_query($conn, 'SELECT count(*) as total FROM user WHERE username = "wecot" FOR UPDATE');
$row = mysqli_fetch_array($res);
if($row['total']>0){
	exit('data exist');
}
 
mysqli_query($conn, "insert into test(username) values ('wecot')");
var_dump('error:'.mysqli_errno($conn));
$insert_id = mysqli_insert_id($conn);
 
mysqli_query($conn, 'COMMIT');
echo 'insert_id:'.$insert_id.'<br>';
 
mysqli_free_result($res);
mysqli_close($conn);

转载请注明:微刻 blog.wecot.cn » Mysql 高并发加锁处理

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址