在使用 CodeIgniter(特别是 CodeIgniter 3)开发过程中,有时候我们需要执行包含多个 SQL 查询的语句块(Multi-Query)。例如,我们可能希望一次性调用多个存储过程,或在一个请求中执行多个查询以提高效率。
但在使用多语句查询时,一个常见问题是:只有第一个结果集可被访问,其它结果集无法获取。这是因为在使用 MySQLi 驱动的情况下,CodeIgniter 并不会自动处理多个结果集。为了解决这个问题,我们就需要手动调用 $this->db->next_result() 方法来清理前一个结果集,并让系统准备好处理下一个。
本文将向你展示如何在 CodeIgniter 中正确使用 next_result() 来处理多语句查询。
假设你有一个存储过程文件,或者直接在控制器中执行类似如下的 SQL:
$sql = "
CALL get_users();
CALL get_orders();
";
为了执行这类多语句 SQL,你可以使用 query() 方法并手动管理结果集:
$result = $this->db->query("CALL get_users();");
if ($result) {
$users = $result->result();
// 清理第一个结果集
$result->free_result();
$this->db->next_result();
// 获取第二个结果集
$result2 = $this->db->query("CALL get_orders();");
if ($result2) {
$orders = $result2->result();
// 再次清理
$result2->free_result();
$this->db->next_result();
}
}
这种方式适用于每次只调用一个存储过程,然后再手动执行下一条语句。但若你希望一次性执行多个 SQL 语句,比如用以下方式:
$sql = "
CALL get_users();
CALL get_orders();
CALL get_products();
";
则可以借助 MySQLi 原生的 multi_query() 功能实现。
在 CodeIgniter 中,如果你使用的是 MySQLi 驱动,你可以这样操作:
$mysqli = $this->db->conn_id; // 获取底层的 MySQLi 连接资源
$sql = "
CALL get_users();
CALL get_orders();
CALL get_products();
";
if ($mysqli->multi_query($sql)) {
do {
if ($result = $mysqli->store_result()) {
// 处理当前结果集
$data[] = $result->fetch_all(MYSQLI_ASSOC);
$result->free();
}
} while ($mysqli->more_results() && $mysqli->next_result());
}
这段代码会依次获取多个结果集,并使用 next_result() 准备好下一个。
虽然你可以直接用 multi_query(),但强烈建议将多语句分开执行,尤其是当你对安全性和稳定性有较高要求时。对于数据库操作,推荐以下做法:
在每次查询后调用 free_result() 和 next_result() 清理连接。
避免在模型中直接写多个 CALL,而是封装为单个调用,逻辑控制放在 PHP 层。
如果必须使用 multi_query(),确保你处理了所有返回的结果集,避免“Commands out of sync”错误。
你可以把这个过程封装成模型方法,返回包含多个数据集的数组:
public function get_multi_data()
{
$mysqli = $this->db->conn_id;
$sql = "
CALL get_users();
CALL get_orders();
CALL get_products();
";
$data = [];
if ($mysqli->multi_query($sql)) {
do {
if ($result = $mysqli->store_result()) {
$data[] = $result->fetch_all(MYSQLI_ASSOC);
$result->free();
}
} while ($mysqli->more_results() && $mysqli->next_result());
}
return $data;
}
控制器中你可以这样调用:
$this->load->model('Data_model');
$result_sets = $this->Data_model->get_multi_data();
$users = $result_sets[0];
$orders = $result_sets[1];
$products = $result_sets[2];
调试多语句查询时,建议开启 CodeIgniter 的日志功能,并观察 application/logs 中的内容,便于排查错误。