"
比如 MySQL,InnoDB,行级锁;
不会出现同时 Update 成功的情况,乐观锁 update 带上了 version 条件,更新不到记录时受影响记录数为 0,后续做相关的业务处理。######ok,我陷入可一个误区,我知道了,是安全的,如果不在其他业务逻辑进行表操作的情况下。######
把版本号当做条件,第二个update 的时候是更新不到记录的,受影响条数是 0,然后抛出异常,回滚事务。######如果两个线程同时获取到相同的version字段,两个同时update ,当前数据记录中version字段值 == 查询出的暂存version字段条件成立,会不会同时更新为相同的结果,最终version字段只是+1?######
Update的时候innoDB会行级锁吧 乐观锁之后第二个应该是影响0行吧 不会报错的 ######
就算2个或者多个线程同时update,那么数据就出现了不确定性,可能是第一个线程update的数据,也可能是后面线程的数据,你说的+1情况,不明白为什么会出现!######
不会的,你第一个update后version+1了,后一个匹配不到数据######
可信答案:
######
这里抛出一个相关的问题: @乌龟壳 version字段一直在自增,当其自增到最大值时,这个临界点该如何处理? 我的做法是引入一个字段flag,用于标记version应该自增还是自减. 乐观锁常用于并发冲突少,同时又要保证正确读写的场景. 我把乐观锁用到了程序读写用户会话session表上:
$table = $app['db_prefix'].'session';
switch(true) {
//version 类型 smallint 范围 0 到 65535
case ($app['user']['session_flag'] == 1 && $app['user']['session_version'] != 65535):
$sql = "UPDATE `{$table}` SET `session` = ?, `version` = ?
WHERE `user_id` = ? AND `version` = ? AND `flag` = 1";
$version_increase = true;
break;
case ($app['user']['session_flag'] == 1 && $app['user']['session_version'] == 65535):
$sql = "UPDATE `{$table}` SET `session` = ?, `version` = ?, `flag` = -1
WHERE `user_id` = ? AND `version` = ? AND `flag` = 1";
$version_increase = false;
break;
case ($app['user']['session_flag'] == -1 && $app['user']['session_version'] != 0):
$sql = "UPDATE `{$table}` SET `session` = ?, `version` = ?
WHERE `user_id` = ? AND `version` = ? AND `flag` = -1";
$version_increase = false;
break;
case ($app['user']['session_flag'] == -1 && $app['user']['session_version'] == 0):
$sql = "UPDATE `{$table}` SET `session` = ?, `version` = ?, `flag` = 1
WHERE `user_id` = ? AND `version` = ? AND `flag` = -1";
$version_increase = true;
break;
}
$stmt = $db->prepare($sql);
$stmt->execute(array(
$session,
$version_increase ? $app['user']['session_version'] + 1 : $app['user']['session_version'] - 1,
$app['user']['id'],
$app['user']['session_version'],
));
return ($stmt->rowCount() == 0) ? false : true;
######楼主的头像都被吓黑了######回复
@eechen : 你加一个flag,本质就是用true和false两种状态,配合version字段,组合成最终比smallint还要多两倍的可能的值。实际上你自己造了一个数据类型而已。######回复
@eechen : 到了溢出值回0,和你说的倒退什么的,有啥区别?你只不过用一个flag把可能的值加了一倍而已,但是代码量更大。如果你强调smallint本身的值空间可能不够用,把version字段数据类型设为bigint就能增加何止上亿倍的值空间了,这样不也是简单的溢出就设0就能解决吗?######回复
@乌龟壳 : 你说的情况多个请求到达临界点就可能发生,而我说的配合flag做法,得跨过80多亿次,显然我的做法更严谨,让乐观锁更有意义.######回复
@乌龟壳 : 你说的情况发生的可能性实在太大了,跟我那个没法比,你没必要在这点上狡辩.你如果不考虑临界点问题,那乐观锁本来就没有了意义."