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 продължава да помни старата база данни. Но ако изпълня независимо една от двете заявки, всичко е наред. Може ли някой да помогне с това или да предложи по-добър метод? :(

E.g.

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();
}

In this case, PDO will simply keep checking DATABASE db1name for TABLE yourtable rather than check DATABASE db3name. So PDO will throw an error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'db1name.yourtable' doesn't exist


person Ticabo    schedule 19.08.2010    source източник


Отговори (2)


Имате настройка като сингълтън. Така че следващото ви обаждане до Db::getDB връща оригиналния екземпляр. Ако искате да кеширате екземплярите за времетраенето на скрипта, променете $objInstance на масив и след това вместо да правите:

if (!self::$objInstance){

Do

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

Разбира се, ще трябва да промените редовете за присвояване и реда за връщане, но мисля, че схванахте идеята...

person ircmaxell    schedule 19.08.2010
comment
Благодаря, ircmaxell. Мисля, че това може да проработи, но в момента той декларира, препращайки към този код, който току-що добавих: Фатална грешка: Не може да се използва обект от тип PDO като масив в C:\apache\htdocs\ticabo\includes\db.class.php на ред 29 - person Ticabo; 19.08.2010
comment
Както казах, ще трябва да промените и редовете за присвояване (и реда за връщане). Така че вместо да правите self::$objInstances = new... и return self::$objInstances;, ще трябва да направите съответно self::$objInstances[$signature] = new... и return self::$objInstances[$signature]... - person ircmaxell; 19.08.2010
comment
Ей!!! Подейства като магия!!! Благодаря!!!! Ти си човекът! Сега наистина трябва да науча ООП. :-) - person Ticabo; 19.08.2010
comment
Е, това не е наистина ООП. Това е просто динамично съхраняване на неща в масив... Но се радвам, че можах да помогна... - person ircmaxell; 19.08.2010

Изглежда, че вашата getDB функция ще се свърже само веднъж поради този ред:

if (!self::$objInstance){

Така че първия път, когато го изпълните, той ще се свърже, но при всички следващи повиквания логиката се игнорира.

Предлагам да добавите друго свойство към вашия клас, което съхранява текущия DBType и да промените вашето условие на:

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

Ще трябва да зададете $dbtype във всеки случай на командата за превключване.

person Fosco    schedule 19.08.2010
comment
Благодаря Фоско! Нека опитам да премахна тази линия и да видя как ще стане :) - person Ticabo; 19.08.2010
comment
Страхотна идея, Фоско. Единственият проблем е, че DBtype не разграничава DB :( Работя с много MySQL DB и някои MSSQL и един Oracle. Още може да се добавят по-късно... - person Ticabo; 19.08.2010
comment
добре, тогава някаква комбинация от dbtype и dbindex?... схванахте идеята, нали? - person Fosco; 19.08.2010
comment
Да, Фоско! Схванах идеята. Много съм благодарен за помощта. Ircmaxwell даде подобно предложение, комбинирайки dbtype и dbindex :) Единственият проблем е, че все още не мога да обгърна PDO обекта / масива (засега познавам много малко OOP). Благодаря отново. - person Ticabo; 19.08.2010