PDO拒绝在多个数据库之间切换!

发布于 2024-09-15 07:45:33 字数 3711 浏览 5 评论 0原文

我对 PDO 很陌生,在 PHP 方面也是新手。我目前正在开发一个涉及到许多数据库的连接的项目:MySQL、MSSQL 和 Oracle。因此,我使用下面的类和 PDO 进行连接。类代码如下。

<代码> 数据库类 {

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'); 尝试 { $result = DB::getDB("mysql", 3)->query("从 mytable 中选择 myrow");

    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 将简单地继续检查 DATABASE db1name 中的 TABLE yourtable,而不是检查 DATABASE db3name。所以 PDO 会抛出错误:
SQLSTATE[42S02]:未找到基表或视图:1146 表“db1name.yourtable”不存在

Please I am very new to PDO, rather a novice at PHP as well. I am currently working on a project that involves connections to many databases: MySQL, MSSQL and Oracle. So I am using the class below, with PDO, for my connection. The class code is below.


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;      

}

}

And here is the vars include file that is required by the class, I used an array cos I felt this way, new databases can be added easily to the vars file by a non-programmer over time. Of course, here, I have changed the var file values.

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

Now the problem is that, whenever I have connected to one database and try to run my queries on another one, PDO keeps remembering the old database. But if I independently run either query, everything is fine. Can someone please help with this, or suggest a better method? :(

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烂柯人 2024-09-22 07:45:33

您将其设置为单例。因此,您下次调用 Db::getDB 将返回原始实例。如果您想在脚本运行期间缓存实例,请将 $objInstance 更改为数组,然后不要执行以下操作:

if (!self::$objInstance){

Do

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

当然,您需要更改赋值行和返回行也是,但我想你明白了......

You have it setup as a singleton. So your next call to Db::getDB returns the original instance. If you want to cache the instances for the duration of the script, change $objInstance to an array, and then instead of doing:

if (!self::$objInstance){

Do

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

Of course you'll need to change the assignment lines and the return line as well, but I think you get the idea...

み青杉依旧 2024-09-22 07:45:33

由于这一行,您的 getDB 函数似乎只会连接一次:

if (!self::$objInstance){

因此,第一次执行它时,它将连接,但在所有后续调用中,该逻辑将被忽略。

我建议向您的类添加另一个属性来存储当前的 DBType 并将您的条件更改为:

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

您必须在 switch 语句的每个 case 内设置 $dbtype 。

It appears that your getDB function will only connect once because of this line:

if (!self::$objInstance){

So the first time you execute it, it will connect, but on all subsequent calls the logic is ignored.

I suggest adding another property to your class that stores the current DBType and changing your conditional to:

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

You would have to set $dbtype inside each case of the switch statement.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文