实现yii2排它锁与缓存锁
前言
yii2扩展底层实现链式查询中可以使用排它锁,yii2实现用于防止接口并发的缓存锁。
排它锁
提示:排它锁有两种实现方式1.实现方式:原生查询
$sql = 'select * from 表名 where store_id = 1 and id = 1 for update';
return \Yii::$app->db->createCommand($sql)->queryOne();
2.实现方式:扩展底层代码实现模型查询中使用排它锁
//最终实现效果,可在结尾使用->forUpdate()
$form = User::find()->where('store_id 1 and id = 1')->forUpdate()->one();
//实现步骤
1.在\vendor\yiisoft\yii2\db\Query.php中增加以下代码
/** @var bool true-追加悲观锁*/
public $isForUpdate = false;
/**
* 追加悲观锁
* @see forUpdate()
* @return $this the query object itself
*/
public function forUpdate(){
$this->isForUpdate = true;
return $this;
}
2.在\vendor\yiisoft\yii2\db\Query.php中修改create()方法,修改为
public static function create($from)
{
return new self([
'where' => $from->where,
'limit' => $from->limit,
'offset' => $from->offset,
'orderBy' => $from->orderBy,
'indexBy' => $from->indexBy,
'select' => $from->select,
'selectOption' => $from->selectOption,
'distinct' => $from->distinct,
'from' => $from->from,
'groupBy' => $from->groupBy,
'join' => $from->join,
'having' => $from->having,
'union' => $from->union,
'params' => $from->params,
'isForUpdate'=>$from->isForUpdate //增加forupdate进去
]);
}
3.在\vendor\yiisoft\yii2\db\QueryBuilder.php中增加forUpdate()方法
/**
* 格式化所有查询语句后才追加它
* @return string 查询语句末尾追加排它锁语句
*/
public function forUpdate($isForUpdate)
{
if ($isForUpdate) {
return ' for update';
}
return '';
}
4.在\vendor\yiisoft\yii2\db\QueryBuilder.php中修改build()方法,在其最后的return [$sql, $params];上面增加sql链接
$sql .= $this->forUpdate($query->isForUpdate);//确保是在最后面
return [$sql, $params];//这段不要复制上去了
5.在\vendor\yiisoft\yii2\db\QueryInterface.php中增加forUpdate()方法
public function forUpdate();
6.在\vendor\yiisoft\yii2\db\QueryTrait.php中增加forUpdate()方法
public function forUpdate()
{
return $this;
}
7.接下来本可使用AR的->forUpdate()方法了
缓存锁
提示:缓存锁适用于请求接口时的并发限制,距离:用户短时间内多次访问接口,访问只会成功一次,剩余将被拦截 //最终实现效果
public function actionIndex()
{
//第一次输出:访问成功
//第二次输出:已拦截请求
//第N次输出:....
if (Cachelocks('index-' . getCurrentUserId(), 1, 2)) { // 设置2秒缓存锁
return '已拦截请求';
}
return '访问成功';
}
//实现代码
/**
* 缓存锁
* 存在缓存则返回缓存,不存在则设缓存并返回null
* @param string $Cachekey 缓存名称
* @param string $Cachevalue 缓存内容
* @param int $Cachetime 缓存时间 默认3s
* @return mixed
*/
function Cachelock($Cachekey, $Cachevalue, $Cachetime = 3)
{
//存在缓存则返回缓存
if (($value = \Yii::$app->cache->get($Cachekey)) !== false) {
return $value;
}
if ($Cachevalue) {
//不存在缓存,则设置缓存,并返回null
if (!\Yii::$app->cache->set($Cachekey, $Cachevalue, $Cachetime)) {
Yii::warning('Failed to set cache value for key ' . json_encode($Cachekey), __METHOD__);
}
}
return null;
}