[PHP] Atlas.Pdoの使い方その2 ConnectionLocator
こんにちは、ナカエです。
前回に引き続き、Atlasのパッケージ、Atlas.Pdoの使い方を書いていきたいと思います。 本日のメインはConnection Locatorです。
Connection Locator
Atlas.Pdoは複数のデータベースサーバを利用するアプリケーションにも対応しています。 例えば書き込み用のDBが一つ、読み込み用のリードレプリカが複数あるようなケースです。
Atlas.PdoのConnectionLocatorを使うと、読み書きの複数の接続に対し、遅延読み込みされる複数のConnectionオブジェクトを定義し利用することができます。
インスタンス化
\Atlas\Pdo\ConnectionLocatorを利用するには、最低限デフォルトのコネクションの指定が必要です。 デフォルトのコネクションの指定の仕方は複数あります。
DSNから作成
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use \Atlas\Pdo\Connection;
use \Atlas\Pdo\ConnectionLocator;
$locator = ConnectionLocator::new(
'mysql:host=default.db.localhost;dbname=database',
'username',
'password'
);
\Atlas\Pdo\Connectionから作成
$locator2 = ConnectionLocator::new(
Connection::new(
'mysql:host=default.db.localhost;dbname=database',
'username',
'password'
)
);
PDOから作成
$pdo = new \Pdo(
'mysql:host=default.db.localhost;dbname=database',
'username',
'password'
);
$locator3 = ConnectionLocator::new($pdo);
作成してからデフォルトのファクトリを指定
$locator4 = new ConnectionLocator();
$locator4->setDefaultFactory(Connection::factory(
'mysql:host=default.db.localhost;dbname=database',
'username',
'password'
));
Reader/Writerの設定
デフォルトのコネクションに加え、読み書き用のコネクションを設定する方法は2種類あります。
ランタイム設定
インスタンス化後に動的に設定することができます。
$locator = ConnectionLocator::new(
'mysql:host=default.db.localhost;dbname=database',
'username',
'password'
);
// write
$locator->setWriteFactory('master', Connection::factory(
'mysql:host=master.db.localhost;dbname=database',
'username',
'password'
));
// read (slave) #1
// PDOから設定する例
$locator->setReadFactory('slave1', Connection::factory(
new \Pdo(
'mysql:host=slave1.db.localhost;dbname=database',
'username',
'password'
)
));
コンストラクタで設定
コンストラクタでデフォルトの接続と共に指定することもできます。 Dependency Injectionを使う場合に有用です。
// default
$default = Connection::factory(
'mysql:host=default.db.localhost;dbname=database',
'username',
'password'
);
// read connections
$read = [
'slave1' => Connection::factory(
'mysql:host=slave1.db.localhost;dbname=database',
'username',
'password'
),
'slave2' => Connection::factory(
'mysql:host=slave2.db.localhost;dbname=database',
'username',
'password'
),
];
// write connection
$write = [
'master' => Connection::factory(
'mysql:host=master.db.localhost;dbname=database',
'username',
'password'
),
];
$locator = new ConnectionLocator($default, $read, $write);
コネクションの取得
デフォルト・読み・書きそれぞれのコネクションを取得するメソッドが用意されています。
- getDefault(): デフォルトを返す
- getRead(): Readからランダムに一つを選んで返す
- getWrite(): Writeからランダムに一つを選んで返す
getRead()とgetWrite()はランダム選択ですが、初回以降の呼び出しで同じコネクションを返します。また、Read/Writeが設定されていなケースではデフォルトのコネクションを返します。
$read = $locator->getRead();
$results = $read->fetchAll('SELECT * FROM users');
$readAgain = $locator->getRead();
assert($read === $readAgain); // true
// 名前を指定して取得することも可能
try {
$foo = $locator->get(ConnectionLocator::READ, 'foo');
$bar = $locator->get(ConnectionLocator::WRITE, 'bar');
} catch (\Atlas\Pdo\Exception $e) {
// 指定した名前の接続が見つからなかったら例外
var_dump($e->getMessage());
}
クエリロガー
\Atlas\Pdo\Connection同様に、ConnectionLocatorもクエリのロギング機構を持ちます。 コネクションごとに設定する手間が省けます。
class MyQueryLogger {
public function __invoke(array $entry)
{
echo PHP_EOL . 'クエリ実行:' . PHP_EOL;
var_dump($entry);
}
}
$locator->setQueryLogger(new MyQueryLogger());
$locator->logQueries(true);
\Atlas\Pdo\Connectionとほぼ同じクエリの情報を返しますが、どのコネクションで実行されたかを示すconnectionという項目が増えています。
クエリ実行:
array(7) {
["connection"]=>
string(11) "READ:slave2"
["start"]=>
float(1542684431.4657)
["finish"]=>
float(1542684431.4673)
["duration"]=>
float(0.0015730857849121)
["statement"]=>
string(19) "SELECT * FROM users"
["values"]=>
array(0) {
}
["trace"]=>
string(644) "#0 /Users/Nextat/Workspace/atlaspdo_test/vendor/atlas/pdo/src/Connection.php(123): Atlas\Pdo\Connection->addLogEntry(Array)
#1 /Users/Nextat/Workspace/atlaspdo_test/vendor/atlas/pdo/src/LoggedStatement.php(41): Atlas\Pdo\Connection->Atlas\Pdo\{closure}(Array)
#2 /Users/Nextat/Workspace/atlaspdo_test/vendor/atlas/pdo/src/Connection.php(138): Atlas\Pdo\LoggedStatement->execute()
#3 /Users/Nextat/Workspace/atlaspdo_test/vendor/atlas/pdo/src/Connection.php(186): Atlas\Pdo\Connection->perform('SELECT * FROM u...', Array)
#4 /Users/Nextat/Workspace/atlaspdo_test/locator2.php(129): Atlas\Pdo\Connection->fetchAll('SELECT * FROM u...')
#5 {main}"
}
まとめ
Atlas.Pdoの機能はシンプルですが、Connection Locatorを使えばAtlas.Pdoだけでも大規模なアプリケーションに対応することができます。 次回はAtlas.Queryを紹介したいと思います。