【问题标题】:Efficiently use mysqli in object oriented setting在面向对象的设置中有效地使用 mysqli
【发布时间】:2013-09-03 16:44:21
【问题描述】:

我得出的结论是,在 OO 方法中使用 mysqli 比程序方法更好。 (来源:Why is object oriented PHP with mysqli better than the procedural approach?)。但我不太确定我所做的是否真的比我之前所做的更有效率。

我有一个运行 sql 查询的函数。这就是我的代码块的样子:

数据库连接:

function connectDB(){
     $con = mysqli_connect(server, username, password, database);
     return $con;
}

查询函数:

function executeQuery($payload){
     $con = connectDB;
     $result = mysqli_query($con, $payload);
     return $result;
}

如您所见,这不是很有效,因为每次调用 executeQuery 时我都会创建一个新的数据库连接。所以我想我会尝试使用 OOP。

数据库连接(OOP):

function connectDB(){
     $con = new mysqli(server, username, password, database);
     return $con;
}

数据库查询(OOP):

function executeQuery($payload){
     $con = connectDB();
     $result = $con->query($payload);
     return $result;
}

现在对我来说,似乎我显然做错了什么。每次调用查询时,我都会重新实例化 mysqli 类,并且我认为这意味着我正在建立另一个数据库连接。

那么我该如何正确有效地做到这一点呢?

【问题讨论】:

  • 为什么每次都要在这两种情况下调用connectDB 方法?你可以简单地检查一下你是否已经建立了连接,不要再尝试了
  • 这就是我问这个问题的原因。我试图找到一种不必每次都调用它的方法。我不知道有一种方法可以检查连接是否已经存在。感谢那。我会调查的。
  • 那么我将如何处理mysqli 类超出我的executeQuery 方法范围的事实。
  • 我知道这一点。因此我问了这个问题。
  • 您可能会从this solution 中受益(它是为 PDO 设计的,但您可以轻松地为 MySQLi 调整它)。我还建议您使用 report_mode() 启用 MySQLi 基于异常的错误报告。

标签: php performance oop mysqli


【解决方案1】:

那么我该如何正确有效地做到这一点呢?

这实际上与以过程与 OOP 的方式使用 MySQLi 无关。

这与以下行有关:

$con = connectDB();

这将在每次查询时重新创建数据库连接。正如您所指出的,这不是有效的。

有很多方法可以解决这个问题。例如:

  • 直接使用mysqli 类。
  • $con 传递给executeQuery() (Dependency Injection)
  • 使用connectDB()executeQuery() 创建一个DB 类。

我通常直接使用mysqli,因为我认为没有理由包装原生类。我全局创建连接对象(在配置文件中)并在其他对象/函数需要它时使用依赖注入。

【讨论】:

  • 感谢您的回复!
  • 没问题。需要明确的是,全局创建连接对象并不意味着使用global。阅读依赖注入。
【解决方案2】:

虽然你的程序方法很容易解决

function connectDB(){
     return mysqli_connect(server, username, password, database);
}
function executeQuery($payload){
    static $con;
    id (!$con)
    { 
        $con = connectDB();
    }
    return $con->query($payload);
}

OOP 方法确实会更好。我不是 OOP 专业人士,但你可以看看 my approach,它至少使用封装来隐藏所有脏活,并提供简洁的方法来获取所需格式的数据,如下所示:

// to get a username
$name = $db->getOne('SELECT name FROM table WHERE id = ?i',$_GET['id']);
// to get an array of data
$data = $db->getAll("SELECT * FROM ?n WHERE mod=?s LIMIT ?i",$table,$mod,$limit);
// to get an array indexed by id field
$data = $db->getInd('id','SELECT * FROM ?n WHERE id IN ?a','table', array(1,2));
// to get a single dimensional array
$ids = $db->getCol("SELECT id FROM tags WHERE tagname = ?s",$tag);

// a simple code for the complex INSERT
$data = array('offers_in' => $in, 'offers_out' => $out);
$sql = "INSERT INTO stats SET pid=?i,dt=CURDATE(),?u ON DUPLICATE KEY UPDATE ?u";
$db->query($sql,$pid,$data,$data); 

【讨论】:

  • 我完全同意封装。另一个虽然出现了。使用mysqli->ping 而不是检查$con 是否已填充有什么好处吗?
  • 我认为这里没有使用 ping 的理由
  • 好的。另一个答案建议将我的数据库连接放在 global 变量中。这是一个很好的做法。我的印象是不是。这带来了从不同范围访问我的连接的要点。
  • 我不是全局关键字的敌人。但是使用 OOP 方法似乎完全没有必要,因为您始终可以在构造函数中传递连接变量并将其分配给类变量。然而,虽然你对 OOP 不太熟悉,但我可以在你的函数中使用 global。
  • @YourCommonSense ,你写的和global没什么区别。这是具有相同问题的相同“解决方案”。
【解决方案3】:

作为您确切问题的解决方案:“您不想在每次执行查询时都实例化一个新的 MySQL 连接”,

好吧,我们可以考虑以下几点:

您需要在 GLOBAL 范围内创建连接变量 ($con),这样当通过任何函数访问时,您可以获取之前设置的变量,而不是实例化新变量。

我们可以使用关键字“global”来做到这一点,如下:


连接功能:

function &connectDB(){
     global $con;
     if(empty($con)) {
         $con = new mysqli(server, username, password, database);
     }
     return $con;
}

为了提高性能,我们避免使用引用函数 ( &connectDB ) 克隆/复制连接变量/资源,


查询执行功能

现在我们已经灵活地设置了连接函数,设置queryExecution函数,我们可以使用多个解决方案:

第一个解决方案:

function executeQuery($payload){
     $con = &connectDB(); // do not forget the () , it's good practice
     return $con->query($payload);
}

在这个解决方案中,我们使用了“引用”,所以表达式:

$con = &connectDB();

将变量 $con 设置为全局 $con 的引用/快捷方式(即:仅指向全局变量 $con)

第二种解决方案:

function executeQuery($payload){
     global $con;
     return $con->query($payload);
}

但对于第二种解决方案:函数“connectDB()”必须在调用“executeQuery()”之前至少调用一次,以确保已与数据库建立连接,

请记住,根据此解决方案,多次调用“connectDB()”不会创建多个连接,一旦调用,就会创建连接,如果再次调用,它将返回之前创建的连接。

希望对你有帮助:)

顺便说一句:数据库连接仍然使用 OOP 方法,它比程序方法有更多的好处, & 我推荐使用PDO,它更便携。

【讨论】:

  • 我一直认为拥有一个包含数据库连接的全局变量是不好的做法。
  • 并非所有时候,但最好有一个处理连接的类。它可以在其 PRIVATE 参数之一中携带连接资源,然后应该有一种方法可以返回该连接(如果存在)或创建一个新连接并将其保存到其私有方法中,抱歉解释过多和体面的语言:)。
  • @EvanStoddard 使用全局状态总是是一种不好的做法。每个告诉你其他情况的人都是一无所知。此外,自 PHP 5.0 发布以来,通过引用传递对象是非常愚蠢的,因为它会导致 refcount 出现问题。
  • 我是这么想的,但我不太确定该怎么做。
  • @tereško 我看到了一些关于引用计数问题的内容,但没有进一步阅读。
猜你喜欢
  • 2017-06-04
  • 1970-01-01
  • 2010-11-10
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2017-09-28
  • 1970-01-01
  • 2019-04-13
相关资源
最近更新 更多