У меня есть приложение PHP, которое выросло в размере. База данных использовалась для одного ведущего устройства, но мы намерены изменить это с довольно стандартной репликацией master / slave для производительности и HA.
Поскольку это приложение имеет большой объем чтения, я хотел бы, чтобы чтения были делегированы подчиненным репликам и записывались в мастер.
Приложение основано на Zend Framework 1.1.10 и использует Zend_Db.
Какая была бы лучшая стратегия для этого приложения, чтобы разделить чтение и запись на БД, не переустанавливая код слишком много? (Я понимаю, что здесь, вероятно, будет задействован какой-то рефакторинг).
PS:
Я посмотрел на MySQL Proxy и кажется, что он может прозрачно разделить чтение и запись, сидя между сервером БД и приложением, но я не уверен в проблемах производительности, используя это в производственной среде. У кого-нибудь есть опыт?
Как вы сказали, MySQlProxy может быть решением, но я лично не тестировал его на производстве.
Я использую 2 Db подключения в своем коде для разделения запросов на запись и чтение. 80% обычных задач выполняется с подключением чтения. Вы можете использовать Zend_Application_Resource_Multidb, чтобы обработать это (для меня я сделал эту часть задолго до этого, и я просто храню второе Db-соединение в реестре).
Это легче, когда вы думаете об этой проблеме в начале. Например:
Этот последний момент, транзакции, важен. Если вы хотите управлять транзакциями, важно сделать запросы READ INSIDE транзакцией с подключением WRITE . Как и все прочитанные до того, как транзакция будет считаться устаревшей, и если ваш бэкэнд базы данных блокирует блокировки, вам придется сделать запрос на чтение, чтобы получить блокировки. Если бэкэнд базы данных не выполняет неявные чтения, вам также придется выполнять блокировки строк в транзакции. И это означает, что вы не должны полагаться на ключевое слово SELECT, чтобы направить этот запрос на соединение только для чтения.
Если у вас есть хороший уровень использования слоя в вашем приложении, это изменение не очень сложно сделать. Если вы делали хаотические вещи с вашей базой данных / слоем DAO, тогда … это может быть сложнее.
h2. Zend
Я просто заплатил Zend PDO_MYSQL для разделения соединений чтения и записи. Для этого вам нужно просто указать дополнительные параметры в конфигурациях applicaiton:
'databases' => array ( 'gtf' => array( 'adapter' => 'PDO_MYSQL', 'params' => array( 'host' => 'read.com', 'host_write' => 'write-database-host.com', 'dbname' => 'database', 'username' => 'reader', 'password' => 'reader', 'username_write' => 'writer', 'password_write' => 'writer', 'charset' => 'utf8' ) ),
Здесь все запросы «SELECT …» будут использовать хост . И все остальные запросы будут использовать * host_write *. Если host_write не указан, то все запросы используют хост .
Patch:
diff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php index 5ed3283..d6fccd6 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php @@ -85,6 +85,14 @@ abstract class Zend_Db_Adapter_Abstract * @var object|resource|null */ protected $_connection = null; + + + /** + * Database connection + * + * @var object|resource|null + */ + protected $_connection_write = null; /** * Specifies the case of column names retrieved in queries @@ -299,10 +307,13 @@ abstract class Zend_Db_Adapter_Abstract * * @return object|resource|null */ - public function getConnection() + public function getConnection($read_only_connection = true) { $this->_connect(); - return $this->_connection; + if (!$read_only_connection && $this->_connection_write) + return $this->_connection_write; + else + return $this->_connection; } /** diff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php index d7f6d8a..ee63c59 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php @@ -57,7 +57,7 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract * * @return string */ - protected function _dsn() + protected function _dsn($write_mode = false) { // baseline of DSN parts $dsn = $this->_config; @@ -65,10 +65,15 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract // don't pass the username, password, charset, persistent and driver_options in the DSN unset($dsn['username']); unset($dsn['password']); + unset($dsn['username_write']); + unset($dsn['password_write']); unset($dsn['options']); unset($dsn['charset']); unset($dsn['persistent']); unset($dsn['driver_options']); + + if ($write_mode) $dsn['host'] = $dsn['host_write']; + unset($dsn['host_write']); // use all remaining parts in the DSN foreach ($dsn as $key => $val) { @@ -91,9 +96,6 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract return; } // get the dsn first, because some adapters alter the $_pdoType $dsn = $this->_dsn(); + if ($this->_config['host_write']) + $dsn_write = $this->_dsn(true); // check for PDO extension if (!extension_loaded('pdo')) { /** @@ -120,14 +122,28 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; } try { $this->_connection = new PDO( - $dsn, + $dsn_read, $this->_config['username'], $this->_config['password'], $this->_config['driver_options'] ); + if ($this->_config['host_write']) { + $this->_connection_write = new PDO( + $dsn_write, + $this->_config['username_write'], + $this->_config['password_write'], + $this->_config['driver_options'] + ); + } + $this->_profiler->queryEnd($q); // set the PDO connection to perform case-folding on array keys, or not diff --git a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php index 8bd9f98..4ab81bf 100644 --- a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php +++ b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php @@ -61,8 +61,11 @@ class Zend_Db_Statement_Pdo extends Zend_Db_Statement implements IteratorAggrega */ protected function _prepare($sql) { + + $read_only_connection = preg_match("/^select/i", $sql); + try { - $this->_stmt = $this->_adapter->getConnection()->prepare($sql); + $this->_stmt = $this->_adapter->getConnection($read_only_connection)->prepare($sql); } catch (PDOException $e) { require_once 'Zend/Db/Statement/Exception.php'; throw new Zend_Db_Statement_Exception($e->getMessage());
сdiff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php index 5ed3283..d6fccd6 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php @@ -85,6 +85,14 @@ abstract class Zend_Db_Adapter_Abstract * @var object|resource|null */ protected $_connection = null; + + + /** + * Database connection + * + * @var object|resource|null + */ + protected $_connection_write = null; /** * Specifies the case of column names retrieved in queries @@ -299,10 +307,13 @@ abstract class Zend_Db_Adapter_Abstract * * @return object|resource|null */ - public function getConnection() + public function getConnection($read_only_connection = true) { $this->_connect(); - return $this->_connection; + if (!$read_only_connection && $this->_connection_write) + return $this->_connection_write; + else + return $this->_connection; } /** diff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php index d7f6d8a..ee63c59 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php @@ -57,7 +57,7 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract * * @return string */ - protected function _dsn() + protected function _dsn($write_mode = false) { // baseline of DSN parts $dsn = $this->_config; @@ -65,10 +65,15 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract // don't pass the username, password, charset, persistent and driver_options in the DSN unset($dsn['username']); unset($dsn['password']); + unset($dsn['username_write']); + unset($dsn['password_write']); unset($dsn['options']); unset($dsn['charset']); unset($dsn['persistent']); unset($dsn['driver_options']); + + if ($write_mode) $dsn['host'] = $dsn['host_write']; + unset($dsn['host_write']); // use all remaining parts in the DSN foreach ($dsn as $key => $val) { @@ -91,9 +96,6 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract return; } // get the dsn first, because some adapters alter the $_pdoType $dsn = $this->_dsn(); + if ($this->_config['host_write']) + $dsn_write = $this->_dsn(true); // check for PDO extension if (!extension_loaded('pdo')) { /** @@ -120,14 +122,28 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; } try { $this->_connection = new PDO( - $dsn, + $dsn_read, $this->_config['username'], $this->_config['password'], $this->_config['driver_options'] ); + if ($this->_config['host_write']) { + $this->_connection_write = new PDO( + $dsn_write, + $this->_config['username_write'], + $this->_config['password_write'], + $this->_config['driver_options'] + ); + } + $this->_profiler->queryEnd($q); // set the PDO connection to perform case-folding on array keys, or not diff --git a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php index 8bd9f98..4ab81bf 100644 --- a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php +++ b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php @@ -61,8 +61,11 @@ class Zend_Db_Statement_Pdo extends Zend_Db_Statement implements IteratorAggrega */ protected function _prepare($sql) { + + $read_only_connection = preg_match("/^select/i", $sql); + try { - $this->_stmt = $this->_adapter->getConnection()->prepare($sql); + $this->_stmt = $this->_adapter->getConnection($read_only_connection)->prepare($sql); } catch (PDOException $e) { require_once 'Zend/Db/Statement/Exception.php'; throw new Zend_Db_Statement_Exception($e->getMessage());
сdiff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php index 5ed3283..d6fccd6 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php @@ -85,6 +85,14 @@ abstract class Zend_Db_Adapter_Abstract * @var object|resource|null */ protected $_connection = null; + + + /** + * Database connection + * + * @var object|resource|null + */ + protected $_connection_write = null; /** * Specifies the case of column names retrieved in queries @@ -299,10 +307,13 @@ abstract class Zend_Db_Adapter_Abstract * * @return object|resource|null */ - public function getConnection() + public function getConnection($read_only_connection = true) { $this->_connect(); - return $this->_connection; + if (!$read_only_connection && $this->_connection_write) + return $this->_connection_write; + else + return $this->_connection; } /** diff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php index d7f6d8a..ee63c59 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php @@ -57,7 +57,7 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract * * @return string */ - protected function _dsn() + protected function _dsn($write_mode = false) { // baseline of DSN parts $dsn = $this->_config; @@ -65,10 +65,15 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract // don't pass the username, password, charset, persistent and driver_options in the DSN unset($dsn['username']); unset($dsn['password']); + unset($dsn['username_write']); + unset($dsn['password_write']); unset($dsn['options']); unset($dsn['charset']); unset($dsn['persistent']); unset($dsn['driver_options']); + + if ($write_mode) $dsn['host'] = $dsn['host_write']; + unset($dsn['host_write']); // use all remaining parts in the DSN foreach ($dsn as $key => $val) { @@ -91,9 +96,6 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract return; } // get the dsn first, because some adapters alter the $_pdoType $dsn = $this->_dsn(); + if ($this->_config['host_write']) + $dsn_write = $this->_dsn(true); // check for PDO extension if (!extension_loaded('pdo')) { /** @@ -120,14 +122,28 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; } try { $this->_connection = new PDO( - $dsn, + $dsn_read, $this->_config['username'], $this->_config['password'], $this->_config['driver_options'] ); + if ($this->_config['host_write']) { + $this->_connection_write = new PDO( + $dsn_write, + $this->_config['username_write'], + $this->_config['password_write'], + $this->_config['driver_options'] + ); + } + $this->_profiler->queryEnd($q); // set the PDO connection to perform case-folding on array keys, or not diff --git a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php index 8bd9f98..4ab81bf 100644 --- a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php +++ b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php @@ -61,8 +61,11 @@ class Zend_Db_Statement_Pdo extends Zend_Db_Statement implements IteratorAggrega */ protected function _prepare($sql) { + + $read_only_connection = preg_match("/^select/i", $sql); + try { - $this->_stmt = $this->_adapter->getConnection()->prepare($sql); + $this->_stmt = $this->_adapter->getConnection($read_only_connection)->prepare($sql); } catch (PDOException $e) { require_once 'Zend/Db/Statement/Exception.php'; throw new Zend_Db_Statement_Exception($e->getMessage());
сdiff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php index 5ed3283..d6fccd6 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php @@ -85,6 +85,14 @@ abstract class Zend_Db_Adapter_Abstract * @var object|resource|null */ protected $_connection = null; + + + /** + * Database connection + * + * @var object|resource|null + */ + protected $_connection_write = null; /** * Specifies the case of column names retrieved in queries @@ -299,10 +307,13 @@ abstract class Zend_Db_Adapter_Abstract * * @return object|resource|null */ - public function getConnection() + public function getConnection($read_only_connection = true) { $this->_connect(); - return $this->_connection; + if (!$read_only_connection && $this->_connection_write) + return $this->_connection_write; + else + return $this->_connection; } /** diff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php index d7f6d8a..ee63c59 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php @@ -57,7 +57,7 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract * * @return string */ - protected function _dsn() + protected function _dsn($write_mode = false) { // baseline of DSN parts $dsn = $this->_config; @@ -65,10 +65,15 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract // don't pass the username, password, charset, persistent and driver_options in the DSN unset($dsn['username']); unset($dsn['password']); + unset($dsn['username_write']); + unset($dsn['password_write']); unset($dsn['options']); unset($dsn['charset']); unset($dsn['persistent']); unset($dsn['driver_options']); + + if ($write_mode) $dsn['host'] = $dsn['host_write']; + unset($dsn['host_write']); // use all remaining parts in the DSN foreach ($dsn as $key => $val) { @@ -91,9 +96,6 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract return; } // get the dsn first, because some adapters alter the $_pdoType $dsn = $this->_dsn(); + if ($this->_config['host_write']) + $dsn_write = $this->_dsn(true); // check for PDO extension if (!extension_loaded('pdo')) { /** @@ -120,14 +122,28 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; } try { $this->_connection = new PDO( - $dsn, + $dsn_read, $this->_config['username'], $this->_config['password'], $this->_config['driver_options'] ); + if ($this->_config['host_write']) { + $this->_connection_write = new PDO( + $dsn_write, + $this->_config['username_write'], + $this->_config['password_write'], + $this->_config['driver_options'] + ); + } + $this->_profiler->queryEnd($q); // set the PDO connection to perform case-folding on array keys, or not diff --git a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php index 8bd9f98..4ab81bf 100644 --- a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php +++ b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php @@ -61,8 +61,11 @@ class Zend_Db_Statement_Pdo extends Zend_Db_Statement implements IteratorAggrega */ protected function _prepare($sql) { + + $read_only_connection = preg_match("/^select/i", $sql); + try { - $this->_stmt = $this->_adapter->getConnection()->prepare($sql); + $this->_stmt = $this->_adapter->getConnection($read_only_connection)->prepare($sql); } catch (PDOException $e) { require_once 'Zend/Db/Statement/Exception.php'; throw new Zend_Db_Statement_Exception($e->getMessage());
сdiff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php index 5ed3283..d6fccd6 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php @@ -85,6 +85,14 @@ abstract class Zend_Db_Adapter_Abstract * @var object|resource|null */ protected $_connection = null; + + + /** + * Database connection + * + * @var object|resource|null + */ + protected $_connection_write = null; /** * Specifies the case of column names retrieved in queries @@ -299,10 +307,13 @@ abstract class Zend_Db_Adapter_Abstract * * @return object|resource|null */ - public function getConnection() + public function getConnection($read_only_connection = true) { $this->_connect(); - return $this->_connection; + if (!$read_only_connection && $this->_connection_write) + return $this->_connection_write; + else + return $this->_connection; } /** diff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php index d7f6d8a..ee63c59 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php @@ -57,7 +57,7 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract * * @return string */ - protected function _dsn() + protected function _dsn($write_mode = false) { // baseline of DSN parts $dsn = $this->_config; @@ -65,10 +65,15 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract // don't pass the username, password, charset, persistent and driver_options in the DSN unset($dsn['username']); unset($dsn['password']); + unset($dsn['username_write']); + unset($dsn['password_write']); unset($dsn['options']); unset($dsn['charset']); unset($dsn['persistent']); unset($dsn['driver_options']); + + if ($write_mode) $dsn['host'] = $dsn['host_write']; + unset($dsn['host_write']); // use all remaining parts in the DSN foreach ($dsn as $key => $val) { @@ -91,9 +96,6 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract return; } // get the dsn first, because some adapters alter the $_pdoType $dsn = $this->_dsn(); + if ($this->_config['host_write']) + $dsn_write = $this->_dsn(true); // check for PDO extension if (!extension_loaded('pdo')) { /** @@ -120,14 +122,28 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; } try { $this->_connection = new PDO( - $dsn, + $dsn_read, $this->_config['username'], $this->_config['password'], $this->_config['driver_options'] ); + if ($this->_config['host_write']) { + $this->_connection_write = new PDO( + $dsn_write, + $this->_config['username_write'], + $this->_config['password_write'], + $this->_config['driver_options'] + ); + } + $this->_profiler->queryEnd($q); // set the PDO connection to perform case-folding on array keys, or not diff --git a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php index 8bd9f98..4ab81bf 100644 --- a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php +++ b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php @@ -61,8 +61,11 @@ class Zend_Db_Statement_Pdo extends Zend_Db_Statement implements IteratorAggrega */ protected function _prepare($sql) { + + $read_only_connection = preg_match("/^select/i", $sql); + try { - $this->_stmt = $this->_adapter->getConnection()->prepare($sql); + $this->_stmt = $this->_adapter->getConnection($read_only_connection)->prepare($sql); } catch (PDOException $e) { require_once 'Zend/Db/Statement/Exception.php'; throw new Zend_Db_Statement_Exception($e->getMessage());
сdiff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php index 5ed3283..d6fccd6 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php @@ -85,6 +85,14 @@ abstract class Zend_Db_Adapter_Abstract * @var object|resource|null */ protected $_connection = null; + + + /** + * Database connection + * + * @var object|resource|null + */ + protected $_connection_write = null; /** * Specifies the case of column names retrieved in queries @@ -299,10 +307,13 @@ abstract class Zend_Db_Adapter_Abstract * * @return object|resource|null */ - public function getConnection() + public function getConnection($read_only_connection = true) { $this->_connect(); - return $this->_connection; + if (!$read_only_connection && $this->_connection_write) + return $this->_connection_write; + else + return $this->_connection; } /** diff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php index d7f6d8a..ee63c59 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php @@ -57,7 +57,7 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract * * @return string */ - protected function _dsn() + protected function _dsn($write_mode = false) { // baseline of DSN parts $dsn = $this->_config; @@ -65,10 +65,15 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract // don't pass the username, password, charset, persistent and driver_options in the DSN unset($dsn['username']); unset($dsn['password']); + unset($dsn['username_write']); + unset($dsn['password_write']); unset($dsn['options']); unset($dsn['charset']); unset($dsn['persistent']); unset($dsn['driver_options']); + + if ($write_mode) $dsn['host'] = $dsn['host_write']; + unset($dsn['host_write']); // use all remaining parts in the DSN foreach ($dsn as $key => $val) { @@ -91,9 +96,6 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract return; } // get the dsn first, because some adapters alter the $_pdoType $dsn = $this->_dsn(); + if ($this->_config['host_write']) + $dsn_write = $this->_dsn(true); // check for PDO extension if (!extension_loaded('pdo')) { /** @@ -120,14 +122,28 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; } try { $this->_connection = new PDO( - $dsn, + $dsn_read, $this->_config['username'], $this->_config['password'], $this->_config['driver_options'] ); + if ($this->_config['host_write']) { + $this->_connection_write = new PDO( + $dsn_write, + $this->_config['username_write'], + $this->_config['password_write'], + $this->_config['driver_options'] + ); + } + $this->_profiler->queryEnd($q); // set the PDO connection to perform case-folding on array keys, or not diff --git a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php index 8bd9f98..4ab81bf 100644 --- a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php +++ b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php @@ -61,8 +61,11 @@ class Zend_Db_Statement_Pdo extends Zend_Db_Statement implements IteratorAggrega */ protected function _prepare($sql) { + + $read_only_connection = preg_match("/^select/i", $sql); + try { - $this->_stmt = $this->_adapter->getConnection()->prepare($sql); + $this->_stmt = $this->_adapter->getConnection($read_only_connection)->prepare($sql); } catch (PDOException $e) { require_once 'Zend/Db/Statement/Exception.php'; throw new Zend_Db_Statement_Exception($e->getMessage());
неdiff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php index 5ed3283..d6fccd6 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Abstract.php @@ -85,6 +85,14 @@ abstract class Zend_Db_Adapter_Abstract * @var object|resource|null */ protected $_connection = null; + + + /** + * Database connection + * + * @var object|resource|null + */ + protected $_connection_write = null; /** * Specifies the case of column names retrieved in queries @@ -299,10 +307,13 @@ abstract class Zend_Db_Adapter_Abstract * * @return object|resource|null */ - public function getConnection() + public function getConnection($read_only_connection = true) { $this->_connect(); - return $this->_connection; + if (!$read_only_connection && $this->_connection_write) + return $this->_connection_write; + else + return $this->_connection; } /** diff --git a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php index d7f6d8a..ee63c59 100644 --- a/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php +++ b/Modules/Tools/Externals/Zend/Db/Adapter/Pdo/Abstract.php @@ -57,7 +57,7 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract * * @return string */ - protected function _dsn() + protected function _dsn($write_mode = false) { // baseline of DSN parts $dsn = $this->_config; @@ -65,10 +65,15 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract // don't pass the username, password, charset, persistent and driver_options in the DSN unset($dsn['username']); unset($dsn['password']); + unset($dsn['username_write']); + unset($dsn['password_write']); unset($dsn['options']); unset($dsn['charset']); unset($dsn['persistent']); unset($dsn['driver_options']); + + if ($write_mode) $dsn['host'] = $dsn['host_write']; + unset($dsn['host_write']); // use all remaining parts in the DSN foreach ($dsn as $key => $val) { @@ -91,9 +96,6 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract return; } // get the dsn first, because some adapters alter the $_pdoType $dsn = $this->_dsn(); + if ($this->_config['host_write']) + $dsn_write = $this->_dsn(true); // check for PDO extension if (!extension_loaded('pdo')) { /** @@ -120,14 +122,28 @@ abstract class Zend_Db_Adapter_Pdo_Abstract extends Zend_Db_Adapter_Abstract $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; } try { $this->_connection = new PDO( - $dsn, + $dsn_read, $this->_config['username'], $this->_config['password'], $this->_config['driver_options'] ); + if ($this->_config['host_write']) { + $this->_connection_write = new PDO( + $dsn_write, + $this->_config['username_write'], + $this->_config['password_write'], + $this->_config['driver_options'] + ); + } + $this->_profiler->queryEnd($q); // set the PDO connection to perform case-folding on array keys, or not diff --git a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php index 8bd9f98..4ab81bf 100644 --- a/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php +++ b/Modules/Tools/Externals/Zend/Db/Statement/Pdo.php @@ -61,8 +61,11 @@ class Zend_Db_Statement_Pdo extends Zend_Db_Statement implements IteratorAggrega */ protected function _prepare($sql) { + + $read_only_connection = preg_match("/^select/i", $sql); + try { - $this->_stmt = $this->_adapter->getConnection()->prepare($sql); + $this->_stmt = $this->_adapter->getConnection($read_only_connection)->prepare($sql); } catch (PDOException $e) { require_once 'Zend/Db/Statement/Exception.php'; throw new Zend_Db_Statement_Exception($e->getMessage());