MVCC-多版本并发控制实现乐观锁
MVCC本质
多版本并发控制( Multiversion concurrency control,MCC 或 MVCC ),是数据库管理系统常用的一种并发控制,也用于程序设计语言实现事务内存。
乐观并发控制和悲观并发控制都是通过延迟或者终止相应的事务来解决事务之间的竞争条件来保证事务的可串行化;虽然前面的两种并发控制机制确实能够从根本上解决并发事务的可串行化的问题,但是其实都是在解决写冲突的问题,两者区别在于对写冲突的乐观程度不同(悲观锁也能解决读写冲突问题,但是性能就一般了)。而在实际使用过程中,数据库读请求是写请求的很多倍,我们如果能解决读写并发的问题的话,就能更大地提高数据库的读性能,而这就是多版本并发控制所能做到的事情。
与悲观并发控制可乐观并发控制不同的是,MVCC 是为了解决读写锁造成的多个、长时间的读操作和写死操作问题,也就是解决读写冲突的问题。MVCC 可以与前两者中的任意一种机制结合使用,以提高数据库的读性能。
数据库的悲观锁基于提升并发性能的考虑,一般都同时实现了多版本并发控制。不仅是 MySQL ,包括 Oracle、PostgreSQL 等其他数据库系统也都实现了 MVCC ,但各自的实现机制不尽相同,因为 MVCC 没有一个统一的实现标准。
总的来说, MVCC 的出现假死数据库不满用悲观锁去解决读写冲突问题,因性能不高而提出的解决方案。
实现方式
MVCC 的实现,是通过保存数据在某个时间点的快照来实现的。每个事务读到的数据项都是一个历史快照,被称为快照读,不同于当前读的是快照读读到的数据可能不是最新的,但是快照隔离能使得在整个事务看到的数据都是它启动时的数据状态。而写操作不覆盖已有数据项,而是创建一个新的版本,直至所在事务提交时才变为可见。
一张简化的商品表:
字段 | 描述 |
---|---|
id | 主键id |
product_name | 商品名称 |
product_price | 商品价格 |
product_stock | 商品库存 |
version | 数据版本(新增默认为1) |
<?php
try{
$pdo=new pdo("mysql:host=localhost;dbname=mysql_php", "root", "root",
array(PDO::ATTR_AUTOCOMMIT=>0));//最后是关闭自动提交
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);//开启异常处理
try {
$pdo->beginTransaction();//开启事务处理
$product_id = 1;
$sql = "select * from product where id = {$product_id}";
$restful=$pdo->query($sql)->fetch(PDO::FETCH_ASSOC);
if (!$restful) {
echo "商品不存在:".$e->getMessage();
exit;
}else{
$version = $restful['version'];
$sql = "update product set product_stock=product_stock-1,version = version+1 where id
= {$product_id} and version = {$version}";
$restful=$pdo->exec($sql);
if ($restful) {
$pdo->commit();//事务提交
echo "修改库存成功";
exit;
}else{
echo "修改库存失败";
exit;
}
}
} catch (\Exception $e) {
echo $sql.$e->getMessage();
exit;
}
} catch (\Exception $e) {
echo "数据库连接失败:".$e->getMessage();
exit;
}
?>