MySQL中的乐观锁与悲观锁
在并发控制编程中锁是一个非常重要的概念,锁对于数据和业务一致性的保证起到关键作用,锁可以是程序层面的,也可以是数据库层面的,今天本文就通过MySQL来说明悲观锁与乐观锁两种常见的锁机制。
悲观锁
悲观锁(Pessimistic Lock)的特点是先获取锁,在进行数据操作,最后释放锁。即先锁后查再更新,使用悲观锁的“悲观”的认为是这种获取锁的的可能是非常小的,因而需要确保获取到锁后再进行操作
。这种操作在MySQL中的典型例子就是“select * from goods where id=5 for update”。但是在这种操作下,需要考虑以下情况。
- 使用for update“”的时候要注意此语句必须要
放到事务中执行
,等待事务提交或者回滚后才会释放锁,锁住的行才能允许被其他事务访问。 - 在for update的时候,被扫描的行都会被锁住,所以需要尽可能的保证扫描的行少,
一般都是锁在索引列上面,否则最坏的情况可能导致全表被锁,影响其他业务
。
乐观锁
乐观锁(Optimistic Lock)的特点先进行业务操作,不到万不得已不去拿锁
。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。
/*获取id等于20的行的订单编号和行版本号并通过版本号更新记录*/
$this->trans_begin();//开启事务
$order = $this->get("select order_sn,version from order_info where id=20")
$result = $this->query("update order_info set data = ‘$new_data’, version='$new_data' where version=$version")
if ($result > 0) {
// 乐观锁获取成功,提交事务
$this->trans_commit();
} else {
// 乐观锁获取失败,回滚事务
$this->trans_rollback();
}
通过上述例子可以看到,乐观锁在原有数据没有改变的基础上(版本号没有发生改变)操作成功,改变了回滚进行重试或者其他操作。乐观锁一般需要通过正确的去维护一个版本号字段来进行并发控制。
总结
在取锁的失败率比较低的情况下乐观锁的开销是较小了
,反而取锁失败过高导致事务回滚的开销就比较大。悲观锁在取锁概率较小和业务不是非常复杂的系统中
用的还是比较普遍。