[Laravel Series 4.5] Конфигурация главной-подчиненной библиотеки и генерация синтаксиса
[Laravel Series 4.5] Конфигурация главной-подчиненной библиотеки и генерация синтаксиса

Конфигурация главной-подчиненной библиотеки и генерация грамматики

В нашей онлайн-среде распространенной ситуацией является необходимость разделения главного и подчиненного устройств. Каковы преимущества разделения «главный-подчиненный» и как им соответствовать, не является предметом нашего обучения. Но что вам нужно знать, так это то, что Laravel и все современные фреймворки могут легко настроить разделение главных и подчиненных устройств. Кроме того, нам нужно вернуться к построителю запросов, чтобы увидеть, как генерируется ассемблерный синтаксис нашего собственного оператора SQL.

Соединение с базой данных «главный-подчиненный»

На самом деле конфигурация очень проста, давайте сначала кратко рассмотрим. После этого мы покопаемся в исходном коде, чтобы увидеть, как он пишет в главную библиотеку и читает из подчиненной библиотеки.

Язык кода:javascript
копировать
'mysql2' => [
    'driver' => 'mysql',
    'read' => [
        'host'=>[
            '192.168.56.101'
        ]
    ],
    'write' => [
        'host'=>[
            env('DB_HOST', '127.0.0.1'),
        ]
    ],
    'url' => env('DATABASE_URL'),
//            'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'sticky' => true,
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],
],

Вот измененный файл config/database.php. Как видите, отличие от исходной конфигурации в том, что мы закомментировали исходные хосты, а затем добавили чтение и запись. В этих двух атрибутах хосты можно указывать в виде массива. Таким образом, наши операторы запроса и операторы добавления, удаления и изменения разделены. Оператор запроса будет следовать конфигурации чтения, а другие операторы будут следовать конфигурации записи. В то же время мы также добавили еще один стикер и установили для него значение true. Его функция заключается в том, что в том же запросе, если выполняются операции добавления, удаления и изменения, последующий запрос также будет использовать запись, которая является запросом основной базы данных. Это также связано с тем, что в некоторых компаниях нам необходимо запрашивать данные сразу после обработки данных. Задержка между главным и подчиненным устройствами может привести к тому, что запрошенные подчиненные данные будут неверными (это очень часто встречается в реальном бизнесе). Таким образом, если сразу после операции добавления, удаления и изменения возникает запрос, наш текущий процесс запроса все равно продолжит запрашивать основную базу данных.

Далее мы определяем два маршрута для тестирования.

Язык кода:javascript
копировать
Route::get('ms/test/insert', function(){
    \Illuminate\Support\Facades\DB::connection('mysql2')->table('db_test')->insert(['name'=>'Lily', 'sex'=>2]);
    dd( \Illuminate\Support\Facades\DB::connection('mysql2')->table('db_test')->get()->toArray());
});

Route::get('ms/test/list', function(){
    dd( \Illuminate\Support\Facades\DB::connection('mysql2')->table('db_test')->get()->toArray());
});

После выполнения первого маршрута мы увидим вновь добавленные данные в данных, напечатанных dd(). Затем запросите второй маршрут, и вы обнаружите, что данные остались прежними и новые данные не были добавлены. Поскольку мы не настроили синхронизацию «главный-подчиненный» в MySQL, это также сделано для облегчения отладки и просмотра. Очевидно, что оператор запроса второго маршрута отправляется в другую базу данных.

Что касается того, как добиться разделения чтения и записи, мы рассмотрим метод select() собственного запроса. Найдите метод select() в laravel/framework/src/Illuminate/Database/Connection.php, и вы увидите, что у него также есть третий параметр.

Язык кода:javascript
копировать
public function select($query, $bindings = [], $useReadPdo = true)
{
    return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {
        if ($this->pretending()) {
            return [];
        }

        // For select statements, we'll simply execute the query and return an array
        // of the database result set. Each element in the array will be a single
        // row from the database table, and will either be an array or objects.
        $statement = $this->prepared(
            $this->getPdoForSelect($useReadPdo)->prepare($query)
        );

        $this->bindValues($statement, $this->prepareBindings($bindings));

        $statement->execute();

        return $statement->fetchAll();
    });
}

protected function getPdoForSelect($useReadPdo = true)
{
    return $useReadPdo ? $this->getReadPdo() : $this->getPdo();
}

Параметр $useReadPdo по умолчанию имеет истинное значение. Внутри тела метода метод getPdoForSelect() использует этот параметр. Продолжим смотреть вниз.

Язык кода:javascript
копировать
public function getReadPdo()
{
    if ($this->transactions > 0) {
        return $this->getPdo();
    }

    if ($this->recordsModified && $this->getConfig('sticky')) {
        return $this->getPdo();
    }

    if ($this->readPdo instanceof Closure) {
        return $this->readPdo = call_user_func($this->readPdo);
    }

    return $this->readPdo ?: $this->getPdo();
}

// $this->readPdo laravel/framework/src/Illuminate/Database/Connectors/ConnectionFactory.php createPdoResolverWithHosts

В этом методе больше делать нечего. Главное — использовать. call_user_func() позвонить этому this->readPdo метод, вы можете увидеть это здесь

Язык кода:javascript
копировать
public function setReadPdo($pdo)
{
    $this->readPdo = $pdo;

    return $this;
}

Затем мы отслеживаем резервную копию и переходим непосредственно к классу фабрики соединений в laravel/framework/src/Illuminate/Database/Connectors/ConnectionFactory.php и обнаруживаем, что метод setReadPdo() вызывается в методе createReadWriteConnection().

Язык кода:javascript
копировать
public function make(array $config, $name = null)
{
    $config = $this->parseConfig($config, $name);

    if (isset($config['read'])) {
        return $this->createReadWriteConnection($config);
    }

    return $this->createSingleConnection($config);
}

protected function createReadWriteConnection(array $config)
{
    $connection = $this->createSingleConnection($this->getWriteConfig($config));

    return $connection->setReadPdo($this->createReadPdo($config));
}

protected function createReadWriteConnection(array $config)
{
    $connection = $this->createSingleConnection($this->getWriteConfig($config));

    return $connection->setReadPdo($this->createReadPdo($config));
}

protected function createReadPdo(array $config)
{
    return $this->createPdoResolver($this->getReadConfig($config));
}

protected function createPdoResolver(array $config)
{
    return array_key_exists('host', $config)
                        ? $this->createPdoResolverWithHosts($config)
                        : $this->createPdoResolverWithoutHosts($config);
}

protected function getReadConfig(array $config)
{
    return $this->mergeReadWriteConfig(
        $config, $this->getReadWriteConfig($config, 'read')
    );
}

protected function getReadWriteConfig(array $config, $type)
{
    return isset($config[$type][0])
                    ? Arr::random($config[$type])
                    : $config[$type];
}

Очевидно, что при создании соединения тело метода make() вызывает метод createReadWriteConnection() в зависимости от того, прочитала ли конфигурационный файл конфигурацию. Затем, следуя опубликованному мной коду, вы можете увидеть, что если есть конфигурация чтения, то основное соединение будет создано с использованием конфигурации записи, а затем будет вызван метод setReadPdo() основного соединения и будет создано подчиненное соединение. на основе конфигурации чтения базы данных. Главный объект — это наш объект соединения для записи, а объект соединения для чтения — его дочерний объект.

В методе createPdoResolver() мы видим использование метода createPdoResolverWithHosts(), найденного выше, который генерирует функцию обратного вызова. Теперь каждый должен знать правду. Если вы еще не разобрались, то можете самостоятельно поставить точки останова и выполнить отладку. Ведь расположение кода и файлов указано.

Отсюда мы видим, что Laravel определяет, использовать ли подключение к подчиненной библиотеке для запроса на основе параметров. Я раньше видел исходный код других фреймворков. Будь то Yii или TP, это оценивается на основе того, имеет ли оператор запроса. ВЫБЕРИТЕ символ. Также очень интересно поискать по базе данных. Вы можете изучить ее самостоятельно.

генерация грамматики

После разговора о соединениях давайте вернемся и поговорим об очень важной вещи в соединениях с базой данных, а именно о том, как генерируются операторы SQL. Здесь используется высокий словарь синтаксиса. На самом деле, простое понимание заключается в том, как построитель запросов генерирует операторы SQL. Излишне говорить, что в случае собственного запроса мы можем просто написать оператор SQL самостоятельно и позволить PDO его выполнить. Однако построитель запросов и Eloquent ORM верхнего уровня завершают запрос к базе данных после создания объектов в объектно-ориентированной цепочке, как упоминалось ранее. Среди них должен быть процесс генерации операторов SQL, о чем мы и узнаем дальше.

На самом деле мы построитель запросов Я видел это в той статье Laravel как создать SQL утверждение, помните то, которое мы анализировали update() Метод? Если вы не помните, вы можете вернуться и посмотреть. 【Laravelряд4.2】построитель запросовhttps://mp.weixin.qq.com/s/vUImsLTpEtELgdCTWI6k2A . в исполнении update() При работе мы наконец вошли laravel/framework/src/Illuminate/Database/Query/Grammars/Grammar.php в этом объекте. Судя по названию, это грамматика объект. Этот объект будет отвечать за склеивание реального SQL заявление. Например, позвольте мне взглянуть еще раз insert() наконец прибыл compileInsert() метод.

Язык кода:javascript
копировать
public function compileInsert(Builder $query, array $values)
{
    // Essentially we will force every insert to be treated as a batch insert which
    // simply makes creating the SQL easier for us since we can utilize the same
    // basic routine regardless of an amount of records given to us to insert.
    $table = $this->wrapTable($query->from);

    if (empty($values)) {
        return "insert into {$table} default values";
    }

    if (! is_array(reset($values))) {
        $values = [$values];
    }

    $columns = $this->columnize(array_keys(reset($values)));

    // We need to build a list of parameter place-holders of values that are bound
    // to the query. Each insert should have the exact same amount of parameter
    // bindings so we will loop through the record and parameterize them all.
    $parameters = collect($values)->map(function ($record) {
        return '('.$this->parameterize($record).')';
    })->implode(', ');

    return "insert into $table ($columns) values $parameters";
}

Вот что наконец вернулось SQL Оператор будет передан на соединение, то есть laravel/framework/src/Illuminate/Database/Connection.php в insert() метод для выполнения. Это тот, который мы впервые научились использовать из-за Собственника. запрос называется изметод. Далее давайте посмотрим. get() метод, то есть получить набор результатов запроса изметод.существовать Builder в, получить() Метод вызовет runSelect() метод, этот метод вызовет другой toSql() Метод заключается в получении исходного изметода запроса запроса.

Язык кода:javascript
копировать
public function toSql()
{
    return $this->grammar->compileSelect($this);
}

Как видите, toSql() Вызывается повторно в объекте грамматики compileSelect() метод.

Язык кода:javascript
копировать
public function compileSelect(Builder $query)
{
    if ($query->unions && $query->aggregate) {
        return $this->compileUnionAggregate($query);
    }

    // If the query does not have any columns set, we'll set the columns to the
    // * character to just get all of the columns from the database. Then we
    // can build the query and concatenate all the pieces together as one.
    $original = $query->columns;

    if (is_null($query->columns)) {
        $query->columns = ['*'];
    }

    // To compile the query, we'll spin through each component of the query and
    // see if that component exists. If it does we'll just call the compiler
    // function for the component which is responsible for making the SQL.
    $sql = trim($this->concatenate(
        $this->compileComponents($query))
    );

    if ($query->unions) {
        $sql = $this->wrapUnion($sql).' '.$this->compileUnions($query);
    }

    $query->columns = $original;

    return $sql;
}

Среди них основные SELECT Соединение предложений происходит в compileComponents() Завершено в,Давайте продолжим и займемся этимметод.

Язык кода:javascript
копировать
protected function compileComponents(Builder $query)
{
    $sql = [];

    foreach ($this->selectComponents as $component) {
        if (isset($query->$component)) {
            $method = 'compile'.ucfirst($component);

            $sql[$component] = $this->$method($query, $query->$component);
        }
    }

    return $sql;
}

Кажется, немного неясно? Что делает этот цикл? Фактически, из кода мы видим, что он пересекает локальное свойство. selectComponents и вызывает себя на основе содержимого этого атрибута. Давайте проверим. selectComponents Атрибут обнаружит, что это серия предварительной информации для имен методов.

Язык кода:javascript
копировать
protected $selectComponents = [
    'aggregate',
    'columns',
    'from',
    'joins',
    'wheres',
    'groups',
    'havings',
    'orders',
    'limit',
    'offset',
    'lock',
];

Результатом сращивания в цикле является compileAggregate() 、compileColumns() .... Мы все можем найти эту серию методов, эту кучу методов, существующую в настоящее время в этом файле грамматики. Каждый метод требует передачи дополнительных параметров. query->

Язык кода:javascript
копировать
protected function concatenate($segments)
{
    return implode(' ', array_filter($segments, function ($value) {
        return (string) $value !== '';
    }));
}

Что вы хотите знать о том, где находятся условия и операторы соединения в этих методах compileWheres() и compileJoins(). Я не буду публиковать здесь код, остальное вам предстоит узнать самостоятельно!

Подвести итог

Сегодняшний контент на самом деле относительно простой. Laravel Содержимое базы данных сосредоточено на том, что было изучено ранее. Модель и построитель запросов начальство. Что касается баз данных master-slave, то они, как правило, широко используются в средних и крупных бизнес-проектах, и принцип их реализации на самом деле не сложен. и генерация грамматики Здесь мы в основном рассматриваем генерацию оператора запроса. грамматики, по сравнению с добавлениями, удалениями и изменениями, оператор запроса сохраняется в существовании. where/join/order by/group by и другие функции, поэтому будет сложнее. Конечно, на самом деле все сложнее. ещесуществоватьв конструкторе,после всегосуществоватьгенерация грамматики Это фактически финальный этап сборки. Заинтересованные студенты могут изучить более углубленно. Builder Вышеуказанные функции и методы реализованы в объекте. Полагаю, что после данной серии исследований содержимое этого файла вам уже не незнакомо, а также считаю, что оставшийся контент вы сможете самостоятельно проанализировать самостоятельно. Позже мы выучим еще две простые изибаза. контент, связанный с данными, а именно настройки атрибутов транзакций и PDO, и Redis Простой в использовании.

Справочная документация:

https://learnku.com/docs/laravel/8.x/database/9400#e05dce

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose