rollback(),false;      $obj&"> 数据库并发、事务问题,find、insert操作会重复插入数据吗?-PHP Chinese Network Q&A
数据库并发、事务问题,find、insert操作会重复插入数据吗?
高洛峰
高洛峰 2016-11-07 10:51:20
0
1
676

好像出现了重复插入现象。

$db->begin(); $obj = table::findFirst("code=521"); if( $obj) return $db->rollback(),false; $obj = new table(); $obj->code=521; $obj->create(); $db->commit();

结果好像表里面code为521的数据有十多条。

当时数据库很卡,估计用户点了好几十次按钮。。然后就出现了重复数据。

猜想: 这些并发过来的请求会分不在不同内核中,然后同时运行到find表发现没有code为521的数据,想写入却发现数据库很卡写不进去,然后等数据库正常了,十来个线程都判断没有521这个code然后开始各自执行各自的插入code为521的数据。

这种猜想对吗?事务不就是要保持这两个操作 find 和insert是要原子执行吗?


高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

reply all (1)
三叔

MySQL数据库事务默认的隔离级别是REPEATABLE-READ(可重复读).

[mysqld] transaction-isolation = REPEATABLE-READ

是可以避免脏读和不可重复读的,PHP不需要关心.
脏读:一个事务读到另外一个事务还没有提交的数据.
不可重复读:两次执行同样的查询,可能得到不一样的结果.

楼主要做的应该是想先select查找有没有code是521的记录,没有就insert一条.
既然如此,我觉得楼主为什么不给code这个字段加一个UNIQUE KEY (code)唯一约束呢?
这样做根本不需要开启事务,直接insert,然后根据返回的受影响的行affected_rows来判断插入操作是否成功.

最后再说下事务的原子性.
没有提交的事务,数据库会自动回滚.
但是业务逻辑里是需要开发者根据条件自行进行回滚操作的.
比如:用户1支付50元购买了商品2

           query('SET AUTOCOMMIT=0'); //可以写成 $db->autocommit(false); $db->query('START TRANSACTION'); //可以写成 $db->begin_transaction(); $db->query('UPDATE user SET coin=coin-50 WHERE id=1 AND coin>=50'); $ar1 = $db->affected_rows; $db->query('UPDATE goods SET num=num-1 WHERE id=2 AND num>1'); $ar2 = $db->affected_rows; //两条UPDATE语句都操作成功时(受影响的行都为1)提交事务,否则回滚 if($ar1 === 1 && $ar2 === 1) { $db->query('COMMIT'); //可以写成 $db->commit(); } else { $db->query('ROLLBACK'); //可以写成 $db->rollback(); } $db->query('SET AUTOCOMMIT=1'); //可以写成 $db->autocommit(true);

注意,InnoDB引擎会把写操作(insert/update/delete/select for update)当做事务来处理,所以最后记得SET AUTOCOMMIT=1把事务设置回自动提交,否则需要手动COMMIT普通的写操作.

    Latest Downloads
    More>
    Web Effects
    Website Source Code
    Website Materials
    Front End Template
    About us Disclaimer Sitemap
    php.cn:Public welfare online PHP training,Help PHP learners grow quickly!