本文目录导读:

- 使用 PDO + 自定义连接管理(基础方案)
- 使用 ThinkPHP 框架(内置支持)
- 使用 Laravel 框架(内置读写分离)
- 使用 Hyberf/ThinkSwoole(协程方案)
- 使用重工具库(如 Medoo,支持主从分离)
- 推荐方案
在 PHP 中实现多主多从数据库连接,核心在于读写分离和负载均衡,以下是几种常用的实现方案:
使用 PDO + 自定义连接管理(基础方案)
<?php
class DatabaseManager {
private static $instance = null;
private $writeConnections = [];
private $readConnections = [];
// 主库配置(可多个)
private $writeConfigs = [
[
'host' => '192.168.1.10',
'dbname' => 'test',
'user' => 'admin',
'pass' => 'password',
'port' => 3306
],
[
'host' => '192.168.1.11',
'dbname' => 'test',
'user' => 'admin',
'pass' => 'password',
'port' => 3306
]
];
// 从库配置(可多个)
private $readConfigs = [
[
'host' => '192.168.2.10',
'dbname' => 'test',
'user' => 'readonly',
'pass' => 'read12138',
'port' => 3306
],
[
'host' => '192.168.2.11',
'dbname' => 'test',
'user' => 'readonly',
'pass' => 'read12138',
'port' => 3306
]
];
// 当前连接选择
private $currentConnection = null;
private function __construct() {}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// 获取写连接(轮询策略)
private function getWriteConnection() {
if (empty($this->writeConnections)) {
foreach ($this->writeConfigs as $config) {
$this->writeConnections[] = $this->createConnection($config);
}
}
// 轮询选择主库
static $writeIndex = 0;
$connection = $this->writeConnections[$writeIndex % count($this->writeConnections)];
$writeIndex++;
return $connection;
}
// 获取读连接(负载均衡策略)
private function getReadConnection() {
if (empty($this->readConnections)) {
foreach ($this->readConfigs as $config) {
$this->readConnections[] = $this->createConnection($config);
}
}
// 随机选择从库(也可以使用加权轮询)
$connection = $this->readConnections[array_rand($this->readConnections)];
return $connection;
}
// 创建PDO连接
private function createConnection($config) {
$dsn = "mysql:host={$config['host']};dbname={$config['dbname']};port={$config['port']}";
return new PDO($dsn, $config['user'], $config['pass'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_TIMEOUT => 5
]);
}
// 执行写入操作
public function write($sql, $params = []) {
$conn = $this->getWriteConnection();
$stmt = $conn->prepare($sql);
$stmt->execute($params);
return $stmt->rowCount();
}
// 执行读取操作
public function read($sql, $params = []) {
$conn = $this->getReadConnection();
$stmt = $conn->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
// 获取最后插入ID(从写连接)
public function getInsertId() {
$conn = $this->getWriteConnection();
return $conn->lastInsertId();
}
// 事务处理(必须在主库)
public function transaction($callback) {
$conn = $this->getWriteConnection();
try {
$conn->beginTransaction();
$result = $callback($conn);
$conn->commit();
return $result;
} catch (Exception $e) {
$conn->rollBack();
throw $e;
}
}
}
// 使用示例
$db = DatabaseManager::getInstance();
// 读操作
$users = $db->read("SELECT * FROM users WHERE status = ?", [1]);
// 写操作
$db->write("INSERT INTO users (name, email) VALUES (?, ?)", ['张三', 'zhangsan@example.com']);
$id = $db->getInsertId();
// 事务操作
$db->transaction(function ($conn) {
$conn->exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$conn->exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
});
?>
使用 ThinkPHP 框架(内置支持)
// 数据库配置文件 `config/database.php`
return [
// 默认使用主库
'default' => env('database.driver', 'mysql'),
// 主库配置(多个)
'connections' => [
'mysql' => [
'type' => 'mysql',
'host' => '192.168.1.10,192.168.1.11', // 多个主库
'port' => '3306',
'database' => 'test',
'username' => 'admin',
'password' => 'password',
'charset' => 'utf8mb4',
'prefix' => '',
'debug' => true,
'read' => [
// 从库配置(多个)
[
'host' => '192.168.2.10',
'username' => 'readonly',
'password' => 'read12138'
],
[
'host' => '192.168.2.11',
'username' => 'readonly',
'password' => 'read12138'
]
],
'write' => [
// 写库配置(可选,默认使用主库)
[
'host' => '192.168.1.10',
'username' => 'admin',
'password' => 'password'
]
],
],
],
];
// 使用示例
$users = Db::name('users')->select(); // 自动使用从库
Db::name('users')->insert(['name' => '张三']); // 自动使用主库
使用 Laravel 框架(内置读写分离)
// 数据库配置文件 `config/database.php`
'mysql' => [
'driver' => 'mysql',
'read' => [
// 多个从库
'host' => [
'192.168.2.10',
'192.168.2.11',
'192.168.2.12'
],
],
'write' => [
// 多个主库
'host' => [
'192.168.1.10',
'192.168.1.11'
],
],
'sticky' => true, // 记住会话中已写入的数据库,防止主从同步延迟
'database' => env('DB_DATABASE', 'test'),
'username' => env('DB_USERNAME', 'admin'),
'password' => env('DB_PASSWORD', 'password'),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],
// 使用示例
$users = DB::table('users')->get(); // 自动使用从库
DB::table('users')->insert(['name' => '张三']); // 自动使用主库
使用 Hyberf/ThinkSwoole(协程方案)
<?php
declare(strict_types=1);
namespace App\Pool;
use Hyperf\DbConnection\Db;
use Hyperf\Utils\Coroutine;
class DatabaseService {
// 主库连接池
private static $masterPools = [
'db1' => ['host' => '192.168.1.10'],
'db2' => ['host' => '192.168.1.11']
];
// 从库连接池
private static $slavePools = [
'db1' => ['host' => '192.168.2.10'],
'db2' => ['host' => '192.168.2.11']
];
public static function read(string $sql, array $params = []) {
// 随机从从库池中选择
$pool = self::$slavePools[array_rand(self::$slavePools)];
return Db::connection($pool['host'])->select($sql, $params);
}
public static function write(string $sql, array $params = []) {
// 轮询从主库池中选择
static $index = 0;
$pools = array_values(self::$masterPools);
$pool = $pools[$index % count($pools)];
$index++;
$result = Db::connection($pool['host'])->insert($sql, $params);
return $result;
}
}
使用重工具库(如 Medoo,支持主从分离)
<?php
use Medoo\Medoo;
$database = new Medoo([
'type' => 'mysql',
'master' => [
['host' => '192.168.1.10', 'username' => 'admin', 'password' => 'password'],
['host' => '192.168.1.11', 'username' => 'admin', 'password' => 'password']
],
'slave' => [
['host' => '192.168.2.10', 'username' => 'readonly', 'password' => 'read123'],
['host' => '192.168.2.11', 'username' => 'readonly', 'password' => 'read123']
],
'database' => 'test',
'error' => PDO::ERRMODE_EXCEPTION
]);
// 读操作(自动路由到从库)
$users = $database->select("users", "*");
// 写操作(自动路由到主库)
$database->insert("users", ["name" => "张三"]);
- 读写分离:根据 SQL 类型自动路由
- 负载均衡:主库轮询写入,从库随机/轮询读取
- 故障转移:某个主/从挂掉后可自动切换
- 一致性处理:使用
sticky机制防止主从延迟导致的数据不一致 - 监控与统计:记录各节点 SQL 执行时间和状态
推荐方案
- 简单项目:使用 PDO 自定义连接管理
- 中型项目:使用 ThinkPHP 或 Laravel 内置支持
- 分布式大型项目:使用 MyCat/ShardingSphere 做中间件代理
- 高并发场景:使用 Swoole 协程连接池
选择方案时需要考虑项目的复杂度、团队技术栈和业务需求。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播