質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

2279閲覧

Laravel - クエリの接続先のDBサーバーのホスト名の取得方法を知りたい

adv-yuta

総合スコア1

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2022/04/26 05:01

編集2022/04/27 00:09

前提

Laravelでデータベースをマスター、スレーブの構成にし、MySQLのレプリケーションをしています。readのクエリはマスターに向け、writeのクエリはスレーブに向けています。

config/database.php

1<?php 2 3return [ 4 5 'connections' => [ 6 7 'mysql' => [ 8 'driver' => 'mysql', 9 'read' => [ 10 'host' => env('DB_SLAVE_HOST', '127.0.0.1'), 11 'port' => env('DB_SLAVE_PORT', '3306'), 12 ], 13 'write' => [ 14 'host' => env('DB_MASTER_HOST', '127.0.0.1'), 15 'port' => env('DB_MASTER_PORT', '3306'), 16 ], 17 'sticky' => true, 18 'database' => env('DB_DATABASE', 'database'), 19 'username' => env('DB_USERNAME', 'appuser'), 20 'password' => env('DB_PASSWORD', ''), 21 'unix_socket' => env('DB_SOCKET', ''), 22 'charset' => 'utf8mb4', 23 'collation' => 'utf8mb4_unicode_ci', 24 'prefix' => '', 25 'strict' => true, 26 'engine' => 'InnoDB ROW_FORMAT=DYNAMIC', 27 ],

実現したいこと

それぞれのクエリが向けられているホスト名を確認したいと考えています。
「トランザクション時のクエリ」「同一HTTPでwriteのクエリ発行後のreadのクエリ」「config/database.phpの値をconnections.mysql.read.hostをhostの情報で上書きした場合のreadのクエリ」など様々なクエリを想定しており、それぞれのクエリが向けられているホスト名をデバッグして確実に確認したいです。

試したこと

  • toSql()メソッドですとクエリはデバッグできるのですが、ホスト名は確認できません。
  • DB::connection()->getConfig()ですとホスト名は取得できるのですが、個々のクエリのホスト名は取得できません。

補足情報(FW/ツールのバージョンなど)

  • Laravel 5.5
  • MySQL 5.6

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/04/26 06:14

確実なのは、Laravel(PHP)側でなく、MySQL側でSQL実行ログをtail -fするとか。
退会済みユーザー

退会済みユーザー

2022/04/26 06:19

試してないのでわかりませんが、laravel-debugbar https://github.com/barryvdh/laravel-debugbar は利用できないんですかね。READとWRITEを分ける設定も考慮してくれそうな気がするんですが。
adv-yuta

2022/04/26 06:25

> 確実なのは、Laravel(PHP)側でなく、MySQL側でSQL実行ログをtail -fするとか。 ありがとうございます!確かにそれぞれのMySQL側でログを確認すれば確実ですね。
adv-yuta

2022/04/26 06:59 編集

> laravel-debugbarは利用できないんですかね。 `debugbar`のデータベースのタブをクリックして確認しましたが、ホスト名の表示はされていなさそうです。
guest

回答1

0

ベストアンサー

※ 手元にマスター・スレーブ環境の動作するものがないので、動作保証はありません。

DataBaseQueryServiceProvider を作成

bash

1php artisan make:provider DataBaseQueryServiceProvider

app/Providers/ に出力された DataBaseQueryServiceProvider.php を以下の内容に編集する

php

1<?php 2 3namespace App\Providers; 4 5use Illuminate\Database\Events\QueryExecuted; 6use Illuminate\Support\ServiceProvider; 7use Carbon\Carbon; 8use DateTime; 9use Illuminate\Database\Events\TransactionBeginning; 10use Illuminate\Database\Events\TransactionCommitted; 11use Illuminate\Database\Events\TransactionRolledBack; 12use Illuminate\Support\Facades\DB; 13use Illuminate\Support\Facades\Event; 14use Illuminate\Support\Facades\Log; 15 16class DataBaseQueryServiceProvider extends ServiceProvider 17{ 18 /** 19 * Register services. 20 * 21 * @return void 22 */ 23 public function register() 24 { 25 // 26 } 27 28 /** 29 * Bootstrap services. 30 * 31 * @return void 32 */ 33 public function boot() 34 { 35 if (!config('app.debug', false)) { 36 return; 37 } 38 39 DB::listen(static function (QueryExecuted $query): void { 40 41 $sql = $query->sql; 42 43 foreach ($query->bindings as $binding) { 44 if (is_string($binding)) { 45 $binding = "'{$binding}'"; 46 } elseif (is_bool($binding)) { 47 $binding = $binding ? '1' : '0'; 48 } elseif (is_int($binding)) { 49 $binding = (string)$binding; 50 } elseif ($binding === null) { 51 $binding = 'NULL'; 52 } elseif ($binding instanceof Carbon) { 53 $binding = "'{$binding->toDateTimeString()}'"; 54 } elseif ($binding instanceof DateTime) { 55 $binding = "'{$binding->format('Y-m-d H:i:s')}'"; 56 } 57 58 $sql = preg_replace('/\\?/', $binding, $sql, 1); 59 } 60 61 $host = $query->connection->getConfig('host'); 62 $time = "{$query->time} ms"; 63 Log::debug('SQL:', compact('host', 'sql', 'time')); 64 }); 65 66 Event::listen(TransactionBeginning::class, static function (TransactionBeginning $event): void { 67 Log::debug('SQL:START TRANSACTION'); 68 }); 69 70 Event::listen(TransactionCommitted::class, static function (TransactionCommitted $event): void { 71 Log::debug('SQL:COMMIT'); 72 }); 73 74 Event::listen(TransactionRolledBack::class, static function (TransactionRolledBack $event): void { 75 Log::debug('SQL:ROLLBACK'); 76 }); 77 } 78}

.env で APP_DEBUG=true にする

config/app.php に以下の行を追記する

php

1 2 /* 3 * Package Service Providers... 4 */ 5 \App\Providers\DataBaseQueryServiceProvider::class, // 追記

上記の対応で、debugbar の messages タブにログが出力されるので、host の項目で確認

イメージ説明

投稿2022/04/26 07:19

phper.k

総合スコア3923

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

adv-yuta

2022/04/26 07:33

ご回答ありがとうございます!コメントしていただいた方法で試してみます。
adv-yuta

2022/04/26 08:02

ご教授していただいたやり方でログを確認できましたが、hostの値がmysqlになっているのが気になっています。。mysql-slaveだと想定通りなのですが。。 `LOG.debug: SQL: {"host":"mysql","sql":"select `title` from `blogs` limit 1","time":"9.81 ms"}` ```config/database.php 'connections' => [ 'mysql' => [ 'driver' => 'mysql', 'url' => env('DATABASE_URL'), 'write' => [ 'host' => 'mysql', 'port' => env('DB_MASTER_PORT', '3306'), ], 'read' => [ 'host' => 'mysql-slave', 'port' => env('DB_SLAVE_PORT', '3306'), ], 'sticky' => true, 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), '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'), ]) : [], ], ```
adv-yuta

2022/04/26 08:06

``` 'write' => [ 'host' => 'mysql-slave', # 実験でmysqlからmysql-slaveに変更 'port' => env('DB_MASTER_PORT', '3306'), ], ``` 上記のようにconfig/database.phpの値を設定すると、ログは以下のようになります。 ``` LOG.debug: SQL: {"host":"mysql-slave","sql":"select `title` from `blogs` limit 1","time":"10.51 ms"} ```
adv-yuta

2022/04/26 08:10

マスターとスレーブでデータに差異を発生させており、select文で取得した値はスレーブから取ってきているのが確実なので、ログで"host":"mysql"と吐かれている理由がわかっていません。。
phper.k

2022/04/26 08:24

回答にも書いてある通り、こちらでは確認できない項目です。 ``` $host = $query->connection->getConfig('host'); ``` ここの部分で dump($query->connection) するなりして、オブジェクトの中身を確認するなどして、適切なプロパティにアクセスをしてみるなど、デバッグしてください。
adv-yuta

2022/04/26 08:31

承知しました!適切なプロパティを探してみます。ありがとうございます。
adv-yuta

2022/04/26 23:54 編集

`$query->connection->readPdo->attributes->CONNECTION_STATUS`の値で判定ができそうです。ありがとうございます。
adv-yuta

2022/04/27 00:06 編集

補足: ```config/database.php 略 'write' => [ 'host' => 'mysql', 'port' => 3360, ], 'read' => [ 'host' => 'mysql-slave', 'port' => 3306, ], 略 ``` 上記の設定の場合、`$query->connection->config`の値は以下の通り、mysql-slaveが存在しません。 ``` #config: array:17 [▼ "driver" => "mysql" "url" => null "host" => "mysql" "port" => "3306" "sticky" => true "database" => "hoge" "username" => "fuga" "password" => "docker#DOCKER1234" "unix_socket" => "" "charset" => "utf8mb4" "collation" => "utf8mb4_unicode_ci" "prefix" => "" "prefix_indexes" => true "strict" => true "engine" => null "options" => [] "name" => "mysql" ] ``` `$query->connection->readPdo->attributes`の値は以下です。CONNECTION_STATUSにmysql-slaveという文字列が確認できます。 ``` #readPdo: PDO {#315 ▼ inTransaction: false attributes: {▼ CASE: NATURAL ERRMODE: EXCEPTION AUTOCOMMIT: 1 PERSISTENT: false DRIVER_NAME: "mysql" SERVER_INFO: "Uptime: 57437 Threads: 5 Questions: 7818 Slow queries: 0 Opens: 150 Flush tables: 1 Open tables: 139 Queries per second avg: 0.136" ORACLE_NULLS: NATURAL CLIENT_VERSION: "mysqlnd 5.0.12-dev - 20150407 - $Id: 38fea24f2847fa7519001be390c98ae0acafe387 $" SERVER_VERSION: "5.7.37-log" STATEMENT_CLASS: array:1 [▶] EMULATE_PREPARES: 0 CONNECTION_STATUS: "mysql-slave via TCP/IP" DEFAULT_FETCH_MODE: BOTH } ```
adv-yuta

2022/04/27 00:08 編集

補足: ```config/database.php 略 'write' => [ 'host' => 'mysql', 'port' => 3360, ], 'read' => [ 'host' => 'mysql', 'port' => 3306, ], 略 ``` 上記のように設定すると、`$query->connection->readPdo->attributes->CONNECTION_STATUS`の値は`mysql via TCP/IP`となり、mysqlが確認できます。 ```config/database.php 略 'host' => 'mysql', 'port' => 3360, ], 略 ``` 上記のようにwrite、readの設定を廃止すると`$query->connection->readPdo`の値が`null`となります。 したがって、`$query->connection->readPdo->attributes->CONNECTION_STATUS`の値で各クエリの接続先のDBサーバーのホスト名が確認できます。`$query->connection->readPdo`の値がnullの場合は`$query->connection->getConfig('host');`の値を見れば確認できます。
adv-yuta

2022/04/27 03:07 編集

補足: `dump($query->connection->getReadPdo());`でreadPdoにアクセスできますので、以下のようにdumpすることが可能です。 ``` use PDO; Log::debug($query->connection->getReadPdo()->getAttribute(PDO::ATTR_CONNECTION_STATUS)); ```
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問