CodeIgniter 3如何动态切换自动加载的数据库连接
解决CodeIgniter 3动态切换数据库且避免重复代码的方案
我之前也碰到过一模一样的需求——不想在每个控制器里重复写数据库切换逻辑,这里给你两个实用的解决方案:
方案一:扩展核心控制器(推荐)
通过自定义一个基类控制器,让所有需要切换数据库的业务控制器都继承它,这样切换逻辑只需要写一次:
- 在
application/core目录下创建MY_Controller.php文件:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class MY_Controller extends CI_Controller { public function __construct() { parent::__construct(); // 确保Session已加载(如果没在autoload配置里自动加载的话) if (!isset($this->session)) { $this->load->library('session'); } // 从Session读取动态数据库参数 $db_host = $this->session->userdata('db_host'); $db_user = $this->session->userdata('db_user'); $db_pass = $this->session->userdata('db_pass'); $db_name = $this->session->userdata('db_name'); // 只有当Session里存在有效参数时才执行切换 if (!empty($db_host) && !empty($db_name)) { $dynamic_db_config = [ 'hostname' => $db_host, 'username' => $db_user, 'password' => $db_pass, 'database' => $db_name, 'dbdriver' => 'mysqli', // 根据你的数据库驱动调整 'dbprefix' => '', 'pconnect' => FALSE, 'db_debug' => (ENVIRONMENT !== 'production'), 'char_set' => 'utf8', 'dbcollat' => 'utf8_general_ci', 'save_queries' => TRUE ]; // 加载并替换默认的数据库连接 $this->db = $this->load->database($dynamic_db_config, TRUE); } // 否则自动使用你配置的默认数据库连接 } }
- 之后你的业务控制器都继承这个
MY_Controller而不是原生的CI_Controller:
class User extends MY_Controller { public function profile() { // 这里$this->db已经是切换后的数据库连接了 $user_data = $this->db->get('user_profile')->row(); // 后续业务逻辑... } }
如果有部分控制器不需要切换数据库,你可以再创建一个Public_Controller继承原生CI_Controller,专门给这类控制器使用。
方案二:使用CodeIgniter钩子
利用钩子的post_controller_constructor事件,在每个控制器初始化完成后自动执行数据库切换,不需要修改现有控制器的继承关系:
先启用钩子:打开
application/config/config.php,设置$config['enable_hooks'] = TRUE;在
application/config/hooks.php中添加钩子配置:
$hook['post_controller_constructor'] = array( 'class' => 'DbSwitcher', 'function' => 'switchDatabase', 'filename' => 'DbSwitcher.php', 'filepath' => 'hooks' );
- 在
application/hooks目录下创建DbSwitcher.php文件:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class DbSwitcher { public function switchDatabase() { $CI =& get_instance(); // 确保Session可用 if (!isset($CI->session)) { $CI->load->library('session'); } // 从Session获取参数 $db_host = $CI->session->userdata('db_host'); $db_name = $CI->session->userdata('db_name'); if (!empty($db_host) && !empty($db_name)) { $dynamic_config = [ 'hostname' => $db_host, 'username' => $CI->session->userdata('db_user'), 'password' => $CI->session->userdata('db_pass'), 'database' => $db_name, 'dbdriver' => 'mysqli', 'db_debug' => (ENVIRONMENT !== 'production'), 'char_set' => 'utf8', 'dbcollat' => 'utf8_general_ci' ]; // 替换默认数据库连接 $CI->db = $CI->load->database($dynamic_config, TRUE); } } }
如果有个别控制器不需要切换数据库,你可以在钩子类里加判断(比如根据控制器名称跳过)。
注意事项
- 一定要处理Session参数为空的情况,避免因为参数缺失导致数据库连接失败;
- 如果你的Session用数据库存储,要确保默认数据库能正常访问,否则Session无法读取;
- 生产环境建议关闭
db_debug,避免暴露敏感的数据库连接信息。
内容的提问来源于stack exchange,提问作者Charas
相关产品推荐
相关产品推荐

