PDO отказывается переключаться между несколькими базами данных!
Пожалуйста, я очень новичок в PDO, а также новичок в PHP. В настоящее время я работаю над проектом, который предполагает подключение ко многим базам данных: MySQL, MSSQL и Oracle. Поэтому я использую класс ниже, с PDO, для подключения. Код класса приведен ниже.
class db {
private static $objInstance;
/*
* Class Constructor - Create a new database connection if one doesn't exist
* Set to private so no-one can create a new instance via ' = new DB();'
*/
private function __construct() {}
/*
* Like the constructor, we make __clone private so nobody can clone the instance
*/
private function __clone() {}
/*
* Returns DB instance or create initial connection
* @param
* @return $objInstance;
*/
public static function getDB($DBtype, $DBindex) {
include('vars.inc.php');
if (!self::$objInstance){
$DBid = $DBindex - 1;
switch ($DBtype){
case "mysql":
self::$objInstance = new PDO("mysql:host=".$dbvars[$DBid][0].";dbname=".$dbvars[$DBid][1], $dbvars[$DBid][2], $dbvars[$DBid][3]);
break;
case "mssql":
self::$objInstance = new PDO("odbc:Driver={SQL Server};Server=".$dbvars[$DBid][0].";Database=".$dbvars[$DBid][1], $dbvars[$DBid][2], $dbvars[$DBid][3]);
break;
case "oci";
self::$objInstance = new PDO("oci:dbname=//".$dbvars[$DBid][0].":".$dbvars[$DBid][4]."/".$dbvars[$DBid][1], $dbvars[$DBid][2], $dbvars[$DBid][3]);
break;
// Add other case(s) here if another RDBMS (Relational Database Management system) is used
default:
break;
}
self::$objInstance-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$objInstance;
}
}
И вот файл включения vars, который требуется классу, я использовал массив, потому что я чувствовал, что таким образом новые базы данных могут быть легко добавлены в файл vars непрограммистом с течением времени. Конечно, здесь я изменил значения файла var.
define('DB_SERVER', 'localhost'); define('DB_NAME', 'db1name'); define('DB_USER', 'root'); define('DB_PASSWORD', 'rootpass'); define('DB_PORT', ''); define('DB2_SERVER', 'xxx.xxx.xx.xxx'); define('DB2_NAME', 'db2name'); define('DB2_USER', 'root2'); define('DB2_PASSWORD', 'rootpass2'); define('DB2_PORT', ''); define('DB3_SERVER', 'xx.xxx.xxx.xxx'); define('DB3_NAME', db3name'); define('DB3_USER', 'root3'); define('DB3_PASSWORD', 'rootpass3'); define('DB3_PORT', ''); define('DB4_SERVER', 'xxx.xx.xxx.xx'); define('DB4_NAME', 'oracledb'); define('DB4_USER', 'root4'); define('DB4_PASSWORD', 'rootpass4'); define('DB4_PORT', '1521'); $dbvars = array( array(DB_SERVER, DB_NAME , DB_USER, DB_PASSWORD, DB_PORT), array(DB2_SERVER, DB2_NAME , DB2_USER, DB2_PASSWORD, DB2_PORT), array(DB3_SERVER, DB3_NAME , DB3_USER, DB3_PASSWORD, DB3_PORT), array(DB4_SERVER, DB4_NAME , DB4_USER, DB4_PASSWORD, DB4_PORT) );
Теперь проблема в том, что всякий раз, когда я подключаюсь к одной базе данных и пытаюсь выполнить свои запросы к другой, PDO продолжает запоминать старую базу данных. Но если я независимо выполню любой запрос, все будет в порядке. Может кто-нибудь, пожалуйста, помочь с этим или предложить лучший метод? :(
Например,
include('./includes/db.class.php');
try {
$result = DB::getDB("mysql", 3)->query("SELECT myrow FROM mytable");
foreach($result as $row){
print $row['myrow'].'<br />';
}
}catch(PDOException $e){
echo $e->getMessage();
}
echo "<br />Then<br /><hr /><br />";
try {
$result = DB::getDB("mysql", 1)->query("SELECT yourrow FROM yourtable");
foreach($result as $row){
print $row['yourrow'].'<br />' ;
}
}catch(PDOException $e){
echo $e->getMessage();
}
В этом случае PDO будет просто продолжать проверять базу ДАННЫХ db1name на наличие ТАБЛИЦЫ yourtable, а не проверьте имя БАЗЫ ДАННЫХ db3. Таким образом, PDO выдаст ошибку:
SQLSTATE[42S02]: Базовая таблица или представление не найдены: 1146 Таблица 'имя db1.ваш стол" не существует
2 answers
У вас он настроен как одноэлементный. Таким образом, ваш следующий вызов Db::getDB
возвращает исходный экземпляр. Если вы хотите кэшировать экземпляры на время выполнения сценария, измените $objInstance
на массив, а затем вместо этого:
if (!self::$objInstance){
Сделай
$signature = $DBtype . $DBindex;
if (!isset(self::$objInstances[$signature])) {
Конечно, вам нужно будет изменить строки назначения и строку возврата, но я думаю, вы поняли идею...
Похоже, что ваша функция getDb подключится только один раз из-за этой строки:
if (!self::$objInstance){
Таким образом, при первом выполнении он подключится, но при всех последующих вызовах логика игнорируется.
Я предлагаю добавить в ваш класс другое свойство, в котором хранится текущий тип DbType, и изменить ваше условие на:
if (!self::$objInstance || $DBtype != self::$dbtype){
Вам придется установить $dbtype внутри каждого случая оператора switch.