如何在 CodeIgniter 中为不同用户动态切换数据库

本文介绍在 codeigniter(v3.x)中不修改全局 `database.php` 配置文件的前提下,通过运行时创建自定义数据库连接,实现登录后按用户动态切换目标数据库的可靠方案。

在 CodeIgniter 中,database.php 是框架启动时最早加载的配置文件之一,此时控制器、Session、环境变量(如 putenv() 设置的值)均尚未初始化或不可靠访问——因此试图在该文件中读取会话数据、POST 参数或动态环境变量(如 getenv("DB_year"))必然失败。你当前的写法不仅无法生效,还可能引发配置解析错误或缓存不一致问题。

✅ 正确做法是:保留 database.php 中的默认连接(用于登录验证、用户中心等通用操作),在用户成功登录后,于模型(Model)或服务类中按需建立独立的、参数化的数据库连接。CodeIgniter 原生支持此机制,无需修改核心或配置文件。

✅ 推荐实现方式:使用 db_connect() 创建动态连接

在你的登录成功后的业务逻辑(例如 Admin/dashboard 对应的控制器方法或专用模型中),按需初始化专属数据库连接:

// 示例:在 Admin 控制器的 dashboard 方法中
public function dashboard()
{
    // 确保用户已登录且拥有数据库标识(如从 session 或数据库查得)
    $db_name = $this->session->userdata('user_db') ?: 'srs_2019';

    // 构建动态数据库配置数组
    $db_config = [
        'hostname' => 'localhost',
        'username' => 'root',
        'password' => '',
        'database' => $db_name,
        'dbdriver' => 'mysqli',
        'dbprefix' => '',
        'pconnect' => FALSE,
        'db_debug' => (ENVIRONMENT !== 'production'),
        'cache_on' => FALSE,
        'char_set' => 'utf8',
        'dbcollat' => 'utf8_general_ci',
        'swap_pre' => '',
        'encrypt'  => FALSE,
        'compress' => FALSE,
        'stricton' => FALSE,
        'failover' => [],
        'save_queries' => TRUE
    ];

    // 创建并获取独立 DB 实例(注意:返回的是 CI_DB_mysqli_driver 对象)
    $this->dynamic_db = $this->load->database($db_config, TRUE);

    // 现在可安全执行该库下的查询
    $result = $this->dynamic_db->select('*')->from('students')->limit(10)->get()->result();

    $this->load->view('admin/dashboard', ['data' => $result]);
}
? 关键点说明:$this->load->database($config, TRUE) 的第二个参数 TRUE 表示返回新实例而非复用默认连接;该连接完全独立于 $this->db,不会干扰系统默认数据库(如用户认证、日志记录等仍走 default);可将 $db_config 抽取为方法或服务类统一管理,支持多租户、年度分库、地域分库等场景。

✅ 进阶建议:封装为可复用的服务类

为提升可维护性,推荐创建 DatabaseManager 类(放在 application/libraries/):

CI =& get_instance();
    }

    public function get_user_database($db_name)
    {
        if (empty($db_name)) {
            throw new Exception('Database name is required.');
        }

        $config = [
            'hostname' => 'localhost',
            'username' => 'root',
            'password' => '',
            'database' => $db_name,
            'dbdriver' => 'mysqli',
            // ... 其他必要配置(建议从 config/database.php 提取公共项复用)
        ];

        return $this->CI->load->database($config, TRUE);
    }
}

在控制器中调用:

$this->load->library('database_manager');
$this->user_db = $this->database_manager->get_user_database('srs_2025');
$data = $this->user_db->get('reports')->result();

⚠️ 注意事项与最佳实践

  • ❌ 不要尝试在 database.php 中使用 $_SESSION、$this->session 或 putenv() —— 此时 PHP 运行环境尚未加载 CodeIgniter 框架上下文;
  • ✅ 登录前所有操作(含用户名/密码校验、权限检查)必须使用 default 数据库;
  • ✅ 动态库名建议从可信来源获取(如登录后查询用户表中的 tenant_db 字段),避免直接使用 $_POST 值,防止 SQL 注入或越权访问;
  • ✅ 为每个动态连接指定唯一别名(如 $this->db_year_2025),便于调试和内存管理;
  • ✅ 在高并发场景下,注意 MySQL 连接数限制,可启用 pconnect => FALSE 并合理设置 wait_timeout。

通过这种设计,你既能实现“一用户一库”的数据隔离目标,又能保持代码清晰、配置稳定、扩展性强——这才是 CodeIgniter 官方推荐的、生产就绪的多数据库实践方案。