在单个脚本中连接多个数据库的优缺点

Posted

技术标签:

【中文标题】在单个脚本中连接多个数据库的优缺点【英文标题】:Pros and cons of connecting more than one database in single script 【发布时间】:2015-05-19 11:03:14 【问题描述】:

假设用户在单个主机上托管了两个数据库,我需要连接到这两个数据库,这样我就可以随时使用任何表而无需多次添加连接代码。

我已经在 CodeIgniter 中实现了这一点,在 database.php 文件中添加了两个数据库的授权详细信息,并在脚本中使用 $this->load->database('dbname'); 加载所需的数据库。

现在,对于核心 PHP,我们可以这样做:

mysql_connect ('host','user','password','port','dbname'); // connection with one database.   

它与我的第一个数据库连接。

现在,我想连接第二个数据库:

1) 我没有关闭上面的连接并用

与第二个连接
mysql_connect ('host','user','password','port','dbname1');.

2) 这样做会是不好的做法吗?它会消耗更多的对象吗?是否应该要求我们关闭第一个?

【问题讨论】:

请分享您已经尝试过的内容。 已编辑问题!!请检查 旁注:请don't use mysql_* functions,它们不再维护,而是officially deprecated。改为了解prepared statements,并使用PDO 或MySQLi。 This article 将帮助您做出决定。 重复How do you connect to multiple MySQL databases on a single webpage? 它们是否在同一个实例上,只是数据库名称不同? 【参考方案1】:

1) 是否可以在一个脚本中连接多个数据库?

是的,我们可以在同一个脚本中创建多个 MySQL 链接标识符。

2) 不应该用 mysql_close 关闭一个连接并打开一个新连接,而是应该同时打开两个连接,用户可以使用任何数据库中的任何表?

使用 mysql_pconnect 等持久数据库连接

3)如果可能的话,这有什么缺点?会创建两个对象,这会产生问题吗?

我认为除了增加服务器负载之外不会产生任何问题。

【讨论】:

永远不要使用持久连接。 ***.com/questions/3332074/… @DavidSoussan 感谢您分享该链接。不知道那个。但我不同意你的结论,那就是永远不要使用它。该链接警告注意事项,但也提供解决方案。 在使用 SQL 30 年和使用 MySQL 15 年后,我可以说我从未见过持久连接是答案的情况。它们听起来对平面文件程序员很有吸引力。当您遇到真正的性能瓶颈时,请担心这类事情。我敢打赌,当你这样做时,问题不会是数据库连接开销【参考方案2】:

你可以这样使用

$db1 = mysql_connect($hostname, $username, $password); 
$db2 = mysql_connect($hostname, $username, $password, true); 

mysql_select_db('abc', $db1);
mysql_select_db('def', $db2);

对于数据库 1

mysql_query('select * from table1', $db1);

对于数据库 2

mysql_query('select * from table2', $db2);

【讨论】:

感谢您的回复!是否有任何特定理由为与 $db2 的连接添加 true ? 如果您不为第二个数据库传递 true,那么它将只为第一个数据库建立连接,因此必须将第四个参数传递为第二个数据库的 true @Nikul - 想在这里纠正你,你说过“它只会为第一个数据库建立连接,因此有必要将第四个参数传递为第二个数据库的真值”。添加 true 背后的意义是不要让第二个连接覆盖第一个连接。如果你不添加 true 它将做什么是它将覆盖 db1 与 db2 的连接。【参考方案3】:

你试过了吗?

$mysqli1 = new mysqli("example.com", "user", "password", "database1");

$mysqli2 = new mysqli("example.com", "user", "password", "database2");

【讨论】:

【参考方案4】:

如果mysql的用户有两个数据库的权限,你可以从两个数据库中加入两个表 等:

SELECT database1.table.title title1,database2.table.title title2 
FROM database1.table
INNER JOIN database2.table 
ON (database1.table.id=database2.table.id)

【讨论】:

为什么投反对票?好的,答案很简短,但实际上它是这里最好的答案之一。【参考方案5】:

Q:在不关闭之前的数据库的情况下连接其他数据库有什么缺点?

答:当您物理连接到数据库服务器时正在分配资源以与您交互,如果两个数据库位于同一台服务器上,您将不必要地使用可用于处理其他连接或其他活动的资源。因此,您将正确关闭不需要继续使用的连接。

问:这样做是否合适?如果不多次在每个脚本中打开此连接,最好的方法是什么?我希望这仅在核心 php 中完成,因为我已经在 codeigniter 中知道了这一点。

单向会话,但您不能在会话中存储数据库连接。读入PHP.net这个警告:“某些类型的数据不能被序列化,因此存储在会话中。它包括资源变量或具有循环引用的对象(即对象将自身的引用传递给另一个对象)。” MySQL 连接就是这样一种资源。

您必须在每个页面运行时重新连接。

如果您可以通过mysql_pconnect() 依赖连接池,这并不像听起来那么糟糕。连接时,该函数将首先尝试查找已使用相同主机、用户名和密码打开的(永久)链接。如果找到,将返回它的标识符,而不是打开新连接。脚本执行结束时不会关闭与 SQL 服务器的连接。相反,该链接将保持打开状态以供将来使用(mysql_close() 不会关闭由mysql_pconnect() 建立的链接)。

参考:

http://php.net/manual/en/function.mysql-pconnect.php

http://www.php.net/manual/en/intro.session.php

Can't pass mysqli connection in session in php

【讨论】:

这实际上回答了所提出的问题。【参考方案6】:

使用多个数据库的最佳方式是使用 PDO 函数

示例

// database cobfigurations
$config= array(
    // first database
    array(
        'type'=>'mysql',                    // DB type
        'host'=>'localhost',                // DB host
        'dbname'=>'database1',      // DB name
        'user'=>'root',                 // DB username
        'pass'=>'12345',                // DB password
    ),
    // second database
    array(
        'type'=>'mysql',                    // DB type
        'host'=>'localhost',                // DB host
        'dbname'=>'database2',      // DB name
        'user'=>'root',                 // DB username
        'pass'=>'987654',               // DB password
    ),
);
// database connections
$mysql=array();
foreach($config as $con)

    $con=(object)$con;
    $start= new PDO($con->type.':host='.$con->host.';dbname='.$con->dbname.'', $con->user, $con->pass, array(
            // pdo setup
            PDO::ATTR_PERSISTENT            => FALSE,
            PDO::ATTR_DEFAULT_FETCH_MODE    => PDO::FETCH_OBJ,
            PDO::ATTR_ERRMODE               => PDO::ERRMODE_EXCEPTION,
            PDO::MYSQL_ATTR_INIT_COMMAND    => 'SET NAMES UTF8'
    ));

    if ($start && !empty($start) && !is_resource($start))
        $mysql[]=$start;    // connection is OK prepare objects
    else
        $mysql[]=false; // connection is NOT OK, return false


/**********************
 ****  HOW TO USE ****
**********************/ 

// fetch data from database 1
$data1 = $mysql[0]->query("SELECT id, title, text FROM content1")->fetchAll();
if(count($data1)>0)

    foreach($data1 as $i=>$result)
    
        echo $result->id.' '.$result->title.' '.$result->text.'<br>'
    


// fetch data from database 2
$data2 = $mysql[1]->query("SELECT id, title, text FROM content2")->fetchAll();
if(count($data2)>0)

    foreach($data2 as $i=>$result)
    
        echo $result->id.' '.$result->title.' '.$result->text.'<br>'
    

如果您之前没有使用过 PDO,请阅读这个简短的教程:

http://www.mysqltutorial.org/php-querying-data-from-mysql-table/

与 mysql 和 mysqli 连接几乎相同,但更高级、快速和安全。

阅读此文档: http://php.net/manual/en/book.pdo.php

您可以添加超过 2 个数据库

【讨论】:

【参考方案7】:

您可以通过遵循面向对象的方法来做到这一点

首先创建与两个数据库的连接:

$Db1 = new mysqli('localhost','root','','database1'); // this is object of database 1
$Db2 = new mysqli('localhost','root','','database2'); // this is object of database 2

$query1 = 'select * from `table_name_of_database1`';  // Query to be run on DB1
$query2 = 'select * from `table_name_of_database2`';   // Query to be run on DB2

$result1 = $Db1->query($query1); // Executing query on database1 by using $Db1
$result2 = $Db2->query($query2); // Executing query on database2 by using $Db2

echo "<pre>";

/* Print result of $query1 */

if ($result1->num_rows > 0) 
    while($row = $result1->fetch_assoc()) 
        print_r($row);
    
 else 
    echo "0 results";



/*========================================================*/


/* Print result of $query2 */

if ($result2->num_rows > 0) 
    while($row = $result2->fetch_assoc()) 
         print_r($row);
    
 else 
    echo "0 results";

结论:当你想使用database1时使用$Db1对象,如果你想使用database2然后使用$DB2

【讨论】:

【参考方案8】:

我不认为如何同时连接到 2 个数据库是问题,因为您已经成功地完成了它(或者知道如何去做)。我可以从你的问题中收集到这一点。所以我不会展示如何做到这一点。如果需要,请参阅其他答案。

但要直接解决您的问题:

    这样做会是不好的做法吗?通常,您应该尽可能避免同时使用 2 个 DB 连接句柄。如果您只需要从一个 DB 中获取数据并使用它们在另一个 DB 上执行某些操作,那么最好的办法是将 DB1 中的数据放入适当的 PHP 变量中,然后关闭连接;然后进行第二次连接。这比同时打开 2 个数据库连接要便宜。但是,如果您正在执行类似 INSERT INTO db1.table SELECT FROM db2.table 之类的操作,并且还需要根据某些查询的成功或失败来提交或回滚,那么 AFAIK,您需要保持两个连接都打开,直到您的进程结束。你看,总会有取舍。因此,您可以根据自己的应用需求做出决定并承担费用。

作为这个场景的一个实际例子,我曾经做过一个项目,我需要 SELECT 一个 table1,INSERT INTO a table2,如果 INSERT 成功,我从 table1 中删除所有行,如果 DELETE 失败,我回滚INSERT 操作,因为数据不能同时存在于两个表中。

当然,我自己的案例只涉及一个数据库,所以不需要第二个连接。但是假设这两个表位于不同的数据库上,那么这可能与您的情况相似。

    它会消耗更多的对象吗?除了上面 1 中指出的对象外,没有其他对象,即根据您的问题处理的数据库连接。

    我们是否应该强制要求关闭第一个?再次,取决于您的应用程序需求。

【讨论】:

【参考方案9】:

打开 2 个连接并不是为了使用同一服务器上的 2 个数据库中的表。您只需要使用 database.table 表示法。这样做意味着您甚至可以在同一查询中连接来自不同数据库的表

SELECT t1.col1, t1.col2, t2.col2, t2.col2
FROM db1.table1 AS t1 JOIN db2.table1 AS t2 ON t1.col1 = t2.col3

因此,如果您最初连接到 db1,则可以使用 db2 表,同样,如果您连接到 db2,则可以使用 db1 表。

【讨论】:

所以你的意思是说,在上述情况下,如果你已经连接到 db1,你不需要连接到 db2 吗?它会自动访问 db2 的表? 是的,如果您使用我在示例中显示的 database.table 表示法。当然,用户必须对两种模式都拥有必要的权限。 @David Soussan,不。您需要意识到,要获得用于执行查询的数据库连接句柄,您必须指定数据库名称,无论您使用 mysqli 扩展还是 PDO。那么,如何在一个连接句柄中引用 db1 和 db2 呢?你说'当然用户必须对两个模式都有必要的权限',也许你应该先展示如何进行这种连接,然后我们可以学习。 @StephenAdelakun 你错了。大卫是对的。在 MySQL 中,您可以在同一连接甚至同一查询中引用跨不同模式的所有可访问表。这个答案是最相关的。您在连接期间指定的架构将是您选择的(默认)架构,这意味着未指定架构的查询将假定一个。但是你仍然可以在查询中说schemaname.tablename 来引用另一个模式中的表。 @nl-x,我想我现在看到了混乱。因此,您必须已授予用户对这两者的访问权限。好吧,我错过了这一点。事实上,我以前从未这样做过。在这种情况下,大卫是对的。感谢 nl-x 指出这一点。【参考方案10】:

使用 mysqli_connect 代替 mysql_connect

mysqli 提供一次连接多个数据库的功能。

【讨论】:

$Db1 = new mysqli($hostname,$username,$password,$db_name1); // 这是 DB 1 的连接 1 $Db2 = new mysqli($hostname,$username,$password,$db_name2); // 这是 DB 2 的连接 2【参考方案11】:

这是一个简单的类,它会在需要时自动选择所需的数据库。

class Database 

    private $host   = 'host';
    private $user   = 'root';
    private $pass   = 'pass';
    private $dbname = '';

    private $mysqli = null;

    function __construct() 
    
        // dbname is not defined in constructor
        $this->mysqli = new mysqli( $this->host, $this->user, $this->pass );    
    

    function __get( $dbname ) 
    
        // if dbname is different, and select_db() is succesfull, save current dbname
        if ( $this->dbname !== $dbname && $this->mysqli->select_db( $dbname ) ) 
            $this->dbname = $dbname;
        

        // return connection
        return $this->mysqli;
    



// examples
$db = new Database();

$result = $db->db1->query( "SELECT DATABASE()" );
print_r( $result->fetch_row() );

$result = $db->db2->query( "SELECT DATABASE()" );
print_r( $result->fetch_row() );

$result = $db->'dbname with spaces'->query( "SELECT DATABASE()" );
print_r( $result->fetch_row() );

【讨论】:

【参考方案12】:
$con1 = mysql_connect($hostname, $username, $password); 
$con2 = mysql_connect($hostname, $username, $password, true); 

mysql_select_db('database1', $con1);
mysql_select_db('database2', $con2);

然后查询数据库1传递第一个链接标识符:

mysql_query('select * from tablename', $con1);

对于数据库 2,通过第二个:

mysql_query('select * from tablename', $con2);

【讨论】:

【参考方案13】:

为什么需要两个连接?两个数据库的优点/优点实际上主要是性能问题。但是,如果您在同一台机器上,实际上您拥有的唯一优势就是更清晰的分离。因此,最好为表使用一个具有两个不同前缀的数据库。 因此,您可以通过前缀而不是 DB 来分隔不同的数据。

【讨论】:

【参考方案14】:

使用 php 5 版本支持的 PDO 代替 mysql connect

【讨论】:

为什么?你应该提到这一点!我认为这与 PDO/MySql 无关

以上是关于在单个脚本中连接多个数据库的优缺点的主要内容,如果未能解决你的问题,请参考以下文章

数据库迁移:单个创建脚本与更改集

MySQL 连接器 (Python):每个查询的新数据库连接与单个连接

在多个 qt 线程中使用单个 QSqlDatabase 连接

如何使用java代码在单个数据库中一次连接多个模式

单个数据摄取服务与多个单独的微服务? [关闭]

我们可以为单个数据库连接进行多个并行事务吗? [复制]