在codeigniter 3中,手动实例化数据库连接应使用db('group')辅助函数或load_class+initialize,严禁new ci_db;自定义类中需懒加载、避免构造函数调用,并注意配置组存在性与事务隔离。

CodeIgniter 3 中手动实例化数据库连接的正确方式
直接用 $this->load->database() 是最稳妥的,但如果你在非控制器/模型的自定义类里需要独立 DB 实例(比如一个独立的 ReportGenerator 类),就不能依赖 CI 的自动加载上下文。必须显式传入配置并手动初始化。
常见错误是直接 new 一个 CI_DB 类——它根本不能这么用;或者漏掉 active_group 导致连错配置项;又或者没调用 initialize(),结果 query() 报 Call to a member function query() on null。
- 务必从
config/database.php读取完整配置数组(含default或自定义组),不能只传 host/user/pass - 使用
DB()辅助函数(CI 3.1.11+)最简:$db = DB('custom_group');,它内部已处理了驱动加载和初始化 - 若需兼容旧版或更细粒度控制,用
load_class('Database', 'core')+ 手动initialize(),但必须确保$DB对象已完整构建 - 记得检查返回值是否为
FALSE(如配置缺失、扩展未启用),否则后续操作会静默失败
自定义类里怎么安全持有一个 DB 实例
别在构造函数里硬编码配置,也别把 $this->db 当全局变量引用。CI 的 DB 实例不是单例,每次 DB() 调用都新建(除非开启 persistent)。你需要明确生命周期。
典型写法是在方法内按需获取,或在类属性中 lazy 初始化:
class ReportGenerator
{
protected $db;
public function get_report($id)
{
if (!$this->db) {
$this->db = DB('reports'); // 使用 config 中定义的 'reports' 组
}
return $this->db->get_where('reports', ['id' => $id])->row();
}
}
- 不要在
__construct()里直接调DB()—— 此时 CI 的 Loader 还没完全就绪,可能报Unable to load the requested class: Database - 如果类被多次复用(如 CLI 多次调用),每次用完不必
close(),除非你启用了持久连接且担心连接数溢出 - 避免把
$db设为 static,不同请求间会污染连接状态(尤其事务未提交时)
为什么 new CI_DB() 会失败
因为 CI_DB 是抽象基类,实际驱动(如 CI_DB_mysqli_driver)才实现具体逻辑,且依赖 CI 的 Loader 和 Config 类做初始化。直接 new 它只会得到一个未初始化的空壳。
错误示例:$db = new CI_DB(); $db->query(...) → 报 Fatal error: Call to undefined method CI_DB::query()。
- CI 3 的 DB 类设计是工厂模式,必须走
DB()或$this->load->database()流程 - 即使你手动 new 驱动类(如
new CI_DB_mysqli_driver($params)),也绕不开initialize()前的校验和资源分配,极易出错 - 官方文档明确说明:「Do not instantiate the database classes directly」
跨环境切换数据库组的实际坑
开发用 localhost,生产用 aws-rds,你以为只要改 database.php 就行?不一定。手动实例化时,DB('production') 会严格查找配置数组里的 'production' 键,而不是根据 ENVIRONMENT 自动 fallback。
- 如果 config 里只有
default组,而你写DB('production'),会返回FALSE且无提示 - 建议统一用
DB()不带参数,它默认读default;若需多组,确保每个环境的database.php都定义了对应键名 - 调试时加一行
var_dump($db); die;看是否为对象,比抓耳挠腮查 SQL 错误更快
真正麻烦的是事务嵌套和连接复用——手动实例化的 DB 对象不会共享 CI 默认的 $this->db 连接,trans_start() 在不同实例间不互通。这点很容易被忽略,直到线上数据不一致才暴露。











