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.ваш стол" не существует

Author: OMG Ponies, 2010-08-19

2 answers

У вас он настроен как одноэлементный. Таким образом, ваш следующий вызов Db::getDB возвращает исходный экземпляр. Если вы хотите кэшировать экземпляры на время выполнения сценария, измените $objInstance на массив, а затем вместо этого:

if (!self::$objInstance){

Сделай

$signature = $DBtype . $DBindex;
if (!isset(self::$objInstances[$signature])) {

Конечно, вам нужно будет изменить строки назначения и строку возврата, но я думаю, вы поняли идею...

 3
Author: ircmaxell, 2010-08-19 18:09:47

Похоже, что ваша функция getDb подключится только один раз из-за этой строки:

if (!self::$objInstance){

Таким образом, при первом выполнении он подключится, но при всех последующих вызовах логика игнорируется.

Я предлагаю добавить в ваш класс другое свойство, в котором хранится текущий тип DbType, и изменить ваше условие на:

if (!self::$objInstance || $DBtype != self::$dbtype){

Вам придется установить $dbtype внутри каждого случая оператора switch.

 2
Author: Fosco, 2010-08-19 18:07:09