在自定义类中调用 $this->load->database() 返回 NULL,因 $this 非 CI 实例而无 load 属性;正确做法是:CI4 用 Config\Database::connect() 或注册为服务注入,CI3 用 DB('group_name') 并显式赋值变量使用。

自定义类里调用 $this->load->database() 为什么返回 NULL
CodeIgniter 的 $this->load->database() 在控制器或模型中直接调用会自动绑定到 $this->db,但在自定义类(比如 app/Helpers/DbSwitcher.php 或独立 service 类)里,$this 不是 CI 控制器实例,没有 load 属性,自然报 Fatal error: Call to a member function database() on null。
解决方法只有两个,且必须选其一:
- 把自定义类注册为服务并注入
Services(CI4 推荐),例如在app/Config/Services.php中添加静态方法返回新 DB 实例; - 不依赖
$this->load,改用Config\Database::connect('group_name')(CI4)或DB('group_name')(CI3)直接获取连接对象; - CI3 中若坚持用
$this->load,必须让自定义类继承CI_Controller或手动传入$CI =& get_instance(),但极易引发生命周期混乱,不建议。
DB('second_db') 调用后查询仍走默认库
常见错因不是配置写错,而是没把返回的 DB 实例赋给变量,或者误以为它会全局替换 $this->db。CI3 的 DB('group_name') 是工厂函数,返回一个全新 DB 对象,**不会自动挂载到控制器属性上**。
正确写法必须显式接收并使用:
$second_db = DB('second_db');
$result = $second_db->select('*')->from('logs')->get()->result();
如果漏掉 $second_db = 这一步,后续所有 $this->db->... 仍操作默认库,毫无感知地“静默失败”。
额外注意点:
- CI3 多库配置中,
$db['second_db']['hostname']等字段必须完整,不能只写部分键; - CI4 中等价写法是
$db = \Config\Database::connect('second_db'),返回的是ConnectionInterface实例; - 别在循环里反复调用
DB('second_db'),连接复用开销小,但对象创建有成本,可提取为类属性缓存。
切换数据库后事务失效或连接复用异常
多个数据库组共用同一 MySQL 用户、主机、端口时,CI 默认会复用底层 mysqli 连接资源(尤其开启 pconnect 时)。这会导致:事务 start_transaction() 在 A 库生效,但 commit() 却发给了 B 库连接,报错 mysqli_sql_exception: COMMIT is not allowed when implicit autocommit is enabled。
根本解法是强制隔离连接:
- CI3:在
database.php的每个数据库组配置中,显式加上'pconnect' => FALSE(即使你想要持久连接,多库场景下也得关); - CI4:在
app/Config/Database.php的每个$db['group_name']数组中,加'reuse_connection' => FALSE; - 更稳妥的做法:所有跨库事务逻辑都拆到单库内完成,避免在一次请求中对多个 DB 组同时启停事务。
顺带提醒:trans_start()/trans_complete() 只作用于当前 DB 实例,和哪个组无关——所以务必确认你是在 $second_db->trans_start(),而不是 $this->db->trans_start()。
环境变量切换数据库组名时加载失败
用 .env 动态设置数据库组名(如 DB_GROUP=production),再在代码里写 DB(ENV['DB_GROUP']),看似灵活,实则埋雷:
- CI3 不支持运行时读取
.env,ENV是 CI4 概念,CI3 里得用getenv('DB_GROUP'); - 字符串拼接风险:若
ENV['DB_GROUP']为空或含空格,DB(' ')会尝试加载空组名,报Undefined index:; - 配置未预加载:CI3 的
$db全局数组在框架启动时就解析完毕,ENV值变化不会自动刷新$db数组内容,必须手动require_once配置文件或重构为运行时生成。
推荐做法:环境差异用不同配置文件(如 database.production.php),通过 APPPATH.'config/'.ENVIRONMENT.'/database.php' 加载,比字符串拼接安全得多。
最常被忽略的一点:数据库组名区分大小写,DB('Production') 和 DB('production') 是两个完全不同的连接,而错误信息里通常不提示组名是否匹配——只能靠 var_dump(array_keys($db)) 手动核对。

















