隨著業務規模的擴大,數據庫所需處理的數據量也不斷增加,導致單一數據庫面臨著壓力。這時候我們就需要進行數據庫水平分庫操作,將數據分散到不同的數據庫中,從而提高系統的性能和可擴展性。本文將介紹在thinkphp6中如何進行數據庫水平分庫操作。
一、什么是數據庫水平分庫?
數據庫水平分庫是將一個數據庫中的數據分散到多個數據庫中的過程。我們可以將數據按照某種規則(比如按照用戶ID或時間段)劃分到不同的數據庫中,從而降低單一數據庫的負載壓力。同時,在數據量大的情況下,水平分庫還能提高查詢效率,增強數據安全性。
二、Thinkphp6中水平分庫的實現
在thinkphp6中,我們可以通過使用數據庫中間件的方式來實現水平分庫。 將數據庫中間件放在ThinkPHP6的mysql連接中,用于控制分庫。
立即學習“PHP免費學習筆記(深入)”;
- 安裝Thinkswoole
在ThinkPHP6中,采用Thinkswoole作為數據庫中間件。我們需要在項目中安裝Thinkswoole。
在composer.json文件中加入ThinkSwoole的版本信息,然后使用composer進行安裝。
- 修改數據庫配置
首先找到config/database.php文件,將MySQL連接替換成Swoole連接。注釋掉原來的MySQL連接信息:
// 'mysql' => [ // // 默認數據連接標識 // 'default' => env('database.driver', 'mysql'), // // 數據庫連接信息 // 'connections' => [ // 'mysql' => [ // // 數據庫類型 // 'type' => 'mysql', // // 主機地址 // 'host' => env('database.hostname', '127.0.0.1'), // // 數據庫名 // 'database' => env('database.database', ''), // // 用戶名 // 'username' => env('database.username', 'root'), // // 密碼 // 'password' => env('database.password', ''), // // 端口 // 'hostport' => env('database.hostport', '3306'), // // 數據庫連接參數 // 'params' => [], // // 數據庫編碼默認采用utf8 // 'charset' => 'utf8', // // 數據庫表前綴 // 'prefix' => env('database.prefix', ''), // // 數據庫調試模式 // 'debug' => env('database.debug', true), // // 數據庫部署方式:0 集中式(單一服務器),1 分布式(主從服務器) // 'deploy' => 0, // // 數據庫讀寫是否分離 主從式有效 // 'rw_separate' => false, // // 讀寫分離后 主服務器數量 // 'master_num' => 1, // // 指定從服務器序號 // 'slave_no' => '', // // 是否嚴格檢查字段是否存在 // 'fields_strict' => true, // // 數據集返回類型 // 'resultset_type' => 'array', // // 自動寫入時間戳字段 // 'auto_timestamp' => false, // // 時間字段取出后的默認時間格式 // 'datetime_format' => false, // // Builder類 // 'builder' => '', // // Query類 // 'query' => 'thinkdbQuery', // // 是否需要進行SQL性能分析 // 'sql_explain' => false, // ], // ], // ],
添加Swoole連接信息:
// swoole 'swoole' => [ // 默認數據連接標識 'default' => 'swoole', // 數據庫連接信息 'connections' => [ 'swoole' => [ // 數據庫類型 'type' => 'mysql', // 服務器地址 'hostname' => [ '127.0.0.1:3305', '127.0.0.1:3306', ], // 數據庫名 'database' => 'test', // 用戶名 'username' => 'root', // 密碼 'password' => '', // 端口 'hostport' => '', // 數據庫連接參數 'params' => [], // 數據庫編碼默認采用utf8mb4 'charset' => 'utf8mb4', // 數據庫表前綴 'prefix' => '', // 數據庫調試模式 'debug' => true, // 數據庫部署方式:0 集中式(單一服務器),1 分布式(主從服務器) 'deploy' => 0, // 數據庫讀寫是否分離 主從式有效 'rw_separate' => false, // 讀寫分離后 主服務器數量 'master_num' => 1, // 指定從服務器序號 'slave_no' => '', // 自動寫入時間戳字段 'auto_timestamp' => false, // 時間字段取出后的默認時間格式 'datetime_format' => 'Y-m-d H:i:s', // Builder類 'builder' => '', // Query類 'query' => 'thinkdbQuery', // 是否需要進行SQL性能分析 'sql_explain' => false, ], ], ],
上述代碼中,我們定義了兩個服務器地址(127.0.0.1:3305和127.0.0.1:3306),這是為了實現多數據節點的分庫。數據庫名、用戶名、密碼等信息不變。
- 創建數據庫中間件
在app/middleware目錄下創建Db.php的數據庫中間件,添加以下代碼:
<?php namespace appmiddleware; use thinkRequest; use thinkContainer; class Db { public function handle(Request $request, Closure $next) { $serverIds = $this->getServerIds($request); //定義一個連接池 $conns = []; foreach($serverIds as $sid) { $sid = $request->$sid; if(empty($conns[$sid])) { $conns[$sid] = Container::getInstance() ->make('db')->connect($sid); } } Container::getInstance()->bind('db', function() use ($conns) { return $conns; }); return $next($request); } protected function getServerIds(Request $request) { return ['uid']; } }
這里創建了一個名為Db的中間件。在handle方法中,首先獲取當前請求的服務器ID數組。然后依次將這些服務器地址與連接池$cons中已有的地址比較,如果不存在就加入連接池中。最后將連接池$conns綁定到容器實例中。在getServerIds方法中,我們可以設置服務器ID的名稱,這里默認為uid。
- 注冊中間件
在config/middleware.php中加入以下代碼:
return [ ... appmiddlewareDb::class, ];
這段代碼是用來注冊中間件的,在中間件執行活動列表中添加了我們的Db中間件。
- 實現分庫操作
接下來,我們將實現在模型中水平分庫操作。這里以用戶表為例,將用戶ID以10萬為一個庫的界限進行分片操作,表示用戶ID在0-10萬之間的數據存儲在一個數據庫里,以此類推,直到將用戶ID在90萬-100萬之間的數據存儲在第10個數據庫里。
<?php namespace appmodel; use thinkModel; class User extends Model { protected $connection = [ 1 => 'user_1', 2 => 'user_2', 3 => 'user_3', 4 => 'user_4', 5 => 'user_5', 6 => 'user_6', 7 => 'user_7', 8 => 'user_8', 9 => 'user_9', 10 => 'user_10', ]; protected $pk = 'uid'; public function getTableName(): string { $id = ceil($this->id / 100000); return $this->connection[$id] . '.' . $this->table; } }
這里我們定義了10個數據庫連接,每個連接表示一個數據庫分片,實現了水平分庫的目的。接著我們定義getTableName方法,用于獲取當前模型對應的數據表名。根據模型中的主鍵ID值計算出需要訪問的數據庫連接,返回數據庫連接和數據表名稱的組合。
總結:
本文介紹了在ThinkPHP6中的水平分庫操作。隨著業務的不斷擴展和數據規模的增加,水平分庫可以提高系統的性能和可擴展性,以及增強數據安全性。在ThinkPHP6中可以使用Thinkswoole中間件等方法實現水平分庫操作。