DBのMaster-Slave対応
https://github.com/primeminister/cake-master-slave-setup
こちらをCakePHP 2.xに対応させたものです。
ついでに色々いじったのでオリジナルとは使い方が違います。
app/Model/Datasource/Database/MysqlMasterSlave.php
<?php App::uses('Mysql', 'Model/Datasource/Database'); /** * https://github.com/primeminister/cake-master-slave-setup をCake 2.xに対応させたもの。 */ class MysqlMasterSlave extends Mysql { public $description = "MySQL DBO Driver with support for Master/Slave database setup"; /** * Constructor. * * @see DboSource::__construct(); */ public function __construct($config = null, $autoConnect = true) { parent::__construct($config, $autoConnect); } /** * Override execute to use master or slave connection. * * @see DboSource::_execute() */ protected function _execute($sql, $params = array(), $prepareOptions = array()) { $updates = array('CREATE', 'DELETE', 'DROP', 'INSERT', 'UPDATE', 'TRUNCATE', 'REPLACE', 'START TRANSACTION', 'BEGIN', 'COMMIT', 'ROLLBACK'); $trimmed_sql = trim($sql); if (preg_match('/^(SET NAMES)/i', $trimmed_sql)) { // not needed to set a connection // as 'set names' is invoked in the connection constructor // whether 'encoding' is specified on the connection // beware though: explicitly setting a connection here // results in connection constructor being called again // (and again and again ...) } else { $datasource = preg_match('/^(' . implode('|', $updates) . ')/i', $trimmed_sql) ? 'master' : 'default'; $this->setConnection($datasource); //debug($sql); //debug($datasource); } return parent::_execute($sql, $params, $prepareOptions); } /** * Switch the datasource to 'master' when beginning a transaction. * * @see DboSource::begin() */ public function begin() { $this->setConnection('master'); return parent::begin(); } /** * Switch the connection based on name. * Accepted names are 'master' and 'default' (a slave). * If in the middle of a transaction the 'master' connection will always be used. */ protected function setConnection($name = 'default') { if ($this->_transactionStarted) { $name = 'master'; } $datasource = ConnectionManager::getDataSource($name); if (!$datasource->isConnected()) { $datasource->connect(); } $this->_connection = $datasource->getConnection(); } }
app/Config/database.php
class DATABASE_CONFIG { public $default; public $master; private static $selectedSlaveIndex; public function __construct() { $default = array( 'datasource' => 'Database/MysqlMasterSlave', 'persistent' => false, 'prefix' => '', 'encoding' => 'utf8' ); $this->master = array_merge($default, Configure::read('Database.master')); $slaves = array(); foreach (Configure::read('Database.slaves') as $slave) { $slaves[] = array_merge($default, $slave); } if (count($slaves)) { if (!isset(self::$selectedSlaveIndex)) { self::$selectedSlaveIndex = rand(0, count($slaves) - 1); } $this->default = $slaves[self::$selectedSlaveIndex]; } else { $this->default = $this->master; } } }
app/Config/core.php
配列の内容は通常のdatabase.phpに記述するものと同じです。
Configure::write('Database', array( 'master' => array( 'host' => 'Masterホスト名', //'port' => ポート番号, 'database' => 'DB名', 'login' => 'ログイン名', 'password' => 'パスワード' ), 'slaves' => array( array( 'host' => 'Slaveホスト名1', 'port' => ポート番号, 'database' => 'DB名', 'login' => 'ログイン名', 'password' => 'パスワード' ), array( 'host' => 'Slaveホスト名2', ... ) ) ));
あと、トランザクションは
$this->MODEL->getDataSource()->begin();
のようにするか、
app/Model/AppModel.php
public function begin() { $this->getDataSource()->begin(); } public function commit() { $this->getDataSource()->commit(); } public function rollback() { $this->getDataSource()->rollback(); }
のようにしておく。