Как вы думаете, что лучше, использовать прокладку для ActiveRecord, которая запускает методы работающие с базой через try{} catch{} и таким образом может избежать дедлока, или же сделать прокладку непосредственно для \yii\db\Connection ? Только я пока не нашел корневой метод, который делает запрос к PDO.
Код: Выделить всё
namespace app\components\yiiExt;
use yii\db\ActiveRecord;
use yii\db\Exception;
/**
* Class ActiveRecordDeadlockPrevent
* @package app\components\yiiExt
*/
class ActiveRecordDeadlockPrevent extends ActiveRecord
{
const DEADLOCK_USLEEP = 300000;
const DEADLOCK_TPL = '/1213 deadlock/';
const MAX_ATTEMPTS = 5;
protected function callMethod( $name, $args )
{
// Статическая переменная, так как возможны вложенные вызовы.
// Таким образом мы суммарно ограничиваем количество попыток.
static $attempts = 0;
while (++$attempts <= self::MAX_ATTEMPTS) {
try {
$result = call_user_func_array( [ 'parent', $name ], $args );
// После успешного вызова обнуляем число попыток
$attempts = 0;
return $result;
} catch ( Exception $e ) {
// Еще раз нужно проверить число попыток, так как оно могло увеличиться при вложенных вызовах
if ($attempts <= self::MAX_ATTEMPTS && preg_match( self::DEADLOCK_TPL, $e->getMessage() )) {
usleep( self::DEADLOCK_USLEEP );
} else {
throw $e;
}
}
}
return call_user_func_array( [ 'parent', $name ], $args );
}
public function save( $runValidation = true, $attributes = null )
{
return $this->callMethod( __FUNCTION__, func_get_args() );
}
public function updateCounters( $counters, $condition = '', $params = [ ] )
{
return $this->callMethod( __FUNCTION__, func_get_args() );
}
public function update( $runValidation = true, $attributeNames = null )
{
return $this->callMethod( __FUNCTION__, func_get_args() );
}
public function updateAttributes( $attributes )
{
return $this->callMethod( __FUNCTION__, func_get_args() );
}
public function delete()
{
return $this->callMethod( __FUNCTION__, func_get_args() );
}
public function refresh()
{
return $this->callMethod( __FUNCTION__, func_get_args() );
}
public function insert( $runValidation = true, $attributes = null )
{
return $this->callMethod( __FUNCTION__, func_get_args() );
}
public static function updateAll( $attributes, $condition = '', $params = [ ] )
{
return ( new static )->callMethod( __FUNCTION__, func_get_args() );
}
public static function deleteAll( $condition = '', $params = [ ] )
{
return ( new static )->callMethod( __FUNCTION__, func_get_args() );
}
public static function findOne( $condition )
{
return ( new static )->callMethod( __FUNCTION__, func_get_args() );
}
public static function updateAllCounters( $counters, $condition = '', $params = [ ] )
{
return ( new static )->callMethod( __FUNCTION__, func_get_args() );
}
public static function findBySql( $sql, $params = [ ] )
{
return ( new static )->callMethod( __FUNCTION__, func_get_args() );
}
public static function find()
{
return ( new static )->callMethod( __FUNCTION__, func_get_args() );
}
public static function findAll( $condition )
{
return ( new static )->callMethod( __FUNCTION__, func_get_args() );
}
}