Sae*_*iry 7 mysql laravel eloquent
Laravel当我使用执行某些插入/更新查询时,我的应用程序中出现此错误Laravel Eloquent
SQLSTATE[40001]: Serialization failure: 1213 Deadlock found
Run Code Online (Sandbox Code Playgroud)
我怎样才能重新执行查询直到它完成?
以下是在 Laravel 5 中执行此操作的方法(在版本 5.7 和 5.8 上测试):
$numberOfAttempts = 5; // how many times the transaction will retry
// Since we are passing a closure, we need to send
// any "external" variables to it with the `use` keyword
DB::transaction(function () use ($user, $somethingElse) {
// this is just an example
$user->update(...);
$somethingElse->delete();
}, $numberOfAttempts);
Run Code Online (Sandbox Code Playgroud)
这个解决方案适用于 Laravel 5.1,但我相信它可以用于框架的新版本,只需稍作改动。
以下代码假定默认数据库连接名称为“ mysql ”。在config/database.php字段中检查它default。
创建新类扩展Illuminate\Database\MySqlConnection:
namespace App\Helpers\MySQL;
use Closure;
use Exception;
use Illuminate\Database\MySqlConnection;
use Illuminate\Database\QueryException;
use Log;
use PDOException;
/**
* Class DeadlockReadyMySqlConnection
*
* @package App\Helpers
*/
class DeadlockReadyMySqlConnection extends MySqlConnection
{
/**
* Error code of deadlock exception
*/
const DEADLOCK_ERROR_CODE = 40001;
/**
* Number of attempts to retry
*/
const ATTEMPTS_COUNT = 3;
/**
* Run a SQL statement.
*
* @param string $query
* @param array $bindings
* @param \Closure $callback
* @return mixed
*
* @throws \Illuminate\Database\QueryException
*/
protected function runQueryCallback($query, $bindings, Closure $callback)
{
$attempts_count = self::ATTEMPTS_COUNT;
for ($attempt = 1; $attempt <= $attempts_count; $attempt++) {
try {
return $callback($this, $query, $bindings);
} catch (Exception $e) {
if (((int)$e->getCode() !== self::DEADLOCK_ERROR_CODE) || ($attempt >= $attempts_count)) {
throw new QueryException(
$query, $this->prepareBindings($bindings), $e
);
} else {
$sql = str_replace_array('\?', $this->prepareBindings($bindings), $query);
Log::warning("Transaction has been restarted. Attempt {$attempt}/{$attempts_count}. SQL: {$sql}");
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
扩展基本连接工厂Illuminate\Database\Connectors\ConnectionFactory:
namespace App\Helpers\MySQL;
use Config;
use Illuminate\Database\Connectors\ConnectionFactory;
use Illuminate\Database\MySqlConnection;
use Illuminate\Database\PostgresConnection;
use Illuminate\Database\SQLiteConnection;
use Illuminate\Database\SqlServerConnection;
use InvalidArgumentException;
use PDO;
/**
* Class YourAppConnectionFactory
*
* @package App\Helpers\MySQL
*/
class YourAppConnectionFactory extends ConnectionFactory
{
/**
* Create a new connection instance.
*
* @param string $driver
* @param PDO $connection
* @param string $database
* @param string $prefix
* @param array $config
* @return \Illuminate\Database\Connection
*
* @throws InvalidArgumentException
*/
protected function createConnection($driver, PDO $connection, $database, $prefix = '', array $config = [])
{
if ($this->container->bound($key = "db.connection.{$driver}")) {
return $this->container->make($key, [$connection, $database, $prefix, $config]);
}
switch ($driver) {
case 'mysql':
if ($config['database'] === Config::get('database.connections.mysql.database')) {
return new DeadlockReadyMySqlConnection($connection, $database, $prefix, $config);
} else {
return new MySqlConnection($connection, $database, $prefix, $config);
}
case 'pgsql':
return new PostgresConnection($connection, $database, $prefix, $config);
case 'sqlite':
return new SQLiteConnection($connection, $database, $prefix, $config);
case 'sqlsrv':
return new SqlServerConnection($connection, $database, $prefix, $config);
}
throw new InvalidArgumentException("Unsupported driver [$driver]");
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们应该替换标准框架的数据库连接工厂Providers/AppServiceProvider.php(或创建新的服务提供者)
public function register()
{
$this->app->singleton('db.factory', function ($app) {
return new YourAppConnectionFactory($app);
});
}
Run Code Online (Sandbox Code Playgroud)
就是这样!现在所有因死锁而失败的查询都应该重新启动。
| 归档时间: |
|
| 查看次数: |
7574 次 |
| 最近记录: |