This commit is contained in:
Александр Рыбкин 2024-11-20 15:55:20 +03:00
commit 12b888a674
5 changed files with 266 additions and 0 deletions

36
ActiveRecord.php Normal file
View File

@ -0,0 +1,36 @@
<?php
namespace dominion\db;
/**
*
*/
class ActiveRecord extends \yii\db\ActiveRecord
{
protected static $tableSchemaCache = [];
/**
* этот класс позволяет ускорить работу за счет хранения структуры бд
*/
public static function getTableSchema()
{
if(!isset(self::$tableSchemaCache[static::tableName()]))
{
self::$tableSchemaCache[static::tableName()] = parent::getTableSchema();
}
return self::$tableSchemaCache[static::tableName()];
}
/**
* этот класс позволяет ускорить работу за счет отказа от получения списка атрибутов из схемы бд
* /
public function attributes()
{
return array_keys($this->attributeLabels());
}*/
public function init()
{
}
}

61
Command.php Normal file
View File

@ -0,0 +1,61 @@
<?php
namespace dominion\db;
use \Yii;
use \Exception;
use dominion\amqp\AmqpLoger;
/**
* Description of Command
*
* @author noname
*/
class Command extends \yii\db\Command
{
public function prepare($forRead = null)
{
try
{
parent::prepare($forRead);
}
catch (Exception $ex)
{
if(isset($ex->errorInfo, $ex->errorInfo[1]) && $ex->errorInfo[1] >= 2000 && $ex->errorInfo[1] < 3000)
{
AmqpLoger::log('reconnectDB', $ex->errorInfo);
$this->db->close();
$this->db->open();
parent::prepare($forRead);
}
else
{
throw $ex;
}
}
}
protected function internalExecute($rawSql)
{
try
{
parent::internalExecute($rawSql);
}
catch (Exception $ex)
{
if(isset($ex->errorInfo, $ex->errorInfo[1]) && $ex->errorInfo[1] >= 2000 && $ex->errorInfo[1] < 3000)
{
AmqpLoger::log('reconnectDB', $ex->errorInfo);
$this->db->close();
$this->db->open();
$this->pdoStatement = $this->db->pdo->prepare($rawSql);
parent::internalExecute($rawSql);
}
else
{
throw $ex;
}
}
}
}

41
Connection.php Normal file
View File

@ -0,0 +1,41 @@
<?php
namespace dominion\db;
use dominion\amqp\AmqpLoger;
/**
* Description of Connection
*
* @author noname
*/
class Connection extends \yii\db\Connection
{
public $commandClass = 'dominion\db\Command';
public $commandMap = [
'pgsql' => 'dominion\db\Command', // PostgreSQL
'mysqli' => 'dominion\db\Command', // MySQL
'mysql' => 'dominion\db\Command', // MySQL
'sqlite' => 'yii\db\sqlite\Command', // sqlite 3
'sqlite2' => 'yii\db\sqlite\Command', // sqlite 2
'sqlsrv' => 'dominion\db\Command', // newer MSSQL driver on MS Windows hosts
'oci' => 'yii\db\oci\Command', // Oracle driver
'mssql' => 'dominion\db\Command', // older MSSQL driver on MS Windows hosts
'dblib' => 'dominion\db\Command', // dblib drivers on GNU/Linux (and maybe other OSes) hosts
'cubrid' => 'dominion\db\Command', // CUBRID
];
/* public function open()
{
try
{
return parent::open();
}
catch (\Exception $ex)
{
AmqpLoger::log('reconnectDB', $ex->errorInfo);
return parent::open();
}
}*/
}

107
Query.php Normal file
View File

@ -0,0 +1,107 @@
<?php
namespace dominion\db;
use Yii;
/**
* Обертка над стандартным классом \yii\db\Query
* Описывает общие методы для работы, которые могут понадобиться при запросах
*/
class Query extends \yii\db\Query
{
/**
* Множественное обновление записей в таблице по первичному ключу id
* @param string $table Название таблицы бд
* @param array $data Массив данных для обновления
* Например:
* [
* 23 => ['name' => 'обновленное название 23', 'description' => 'обновленное описание 23'],
* 24 => ['name' => 'обновленное название 24', 'description' => 'обновленное описание 24'],
* ]
* Обновит поля name и description у полей с id=23 и id=24 одним запросом
* @return int Количество обновленных записей
*/
public function batchUpdate($table, $data)
{
$fields = [];
$columns = [];
$rows = [];
foreach ($data as $id => $values)
{
if (empty($columns))
{
$fields = array_keys($values);
$columns = array_merge(['id'], $fields);
}
$row = [$id];
foreach ($values as $value)
{
$row[] = $value;
}
$rows[] = $row;
}
$sql = Yii::$app->db->getQueryBuilder()->batchInsert($table, $columns, $rows);
$update = [];
foreach ($fields as $field)
{
$field = Yii::$app->db->quoteColumnName($field);
$update[] = $field . ' = VALUES(' . $field . ')';
}
if (!empty($update))
{
$sql .= ' ON DUPLICATE KEY UPDATE ' . implode(',', $update);
}
\Yii::beginProfile('batchUpdate_' . $table);
$result = Yii::$app->db->createCommand($sql)->execute();
\Yii::endProfile('batchUpdate_' . $table);
return $result;
}
/**
* Множественное добавление записей в таблицу
* @param string $table Название таблицы бд
* @param array $data Массив данных для добавления
* Например:
* [
* ['name' => 'Название 1', 'description' => 'Описание 1'],
* ['name' => 'Название 2', 'description' => 'Описание 2'],
* ]
* Добавит две записи с заполненными полями name и description одним запросом
* Если в массиве больще 5000 элементов, то будет несколько запросов с добавлением по 5000 элементов в одном запросе
*/
public function batchInsert($table, $data)
{
$columns = [];
$rows = [];
foreach ($data as $values)
{
if (empty($columns))
{
$columns = array_keys($values);
}
$row = [];
foreach ($values as $value)
{
$row[] = $value;
}
$rows[] = $row;
}
$limit = 5000;
$count = (int) floor(count($rows) / $limit);
for ($i = 0; $i <= $count; $i++)
{
$partRows = array_slice($rows, $i * $limit, $limit);
Yii::$app->db->createCommand()->batchInsert($table, $columns, $partRows)->execute();
}
}
}

21
composer.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "dominion/db",
"description": "Функционал для работы с db",
"type": "yii2-extension",
"keywords": ["yii2","extension"],
"license": "MIT",
"authors": [
{
"name": "Rybkin Sasha",
"email": "ribkin@dominion.ru"
}
],
"require": {
"yiisoft/yii2": "~2.0.0"
},
"autoload": {
"psr-4": {
"dominion\\db\\": ""
}
}
}