本文目录导读:

在 Laravel 中实现读写分离有多种方式,我来详细介绍几种常用方法:
配置文件方式(最简单)
第一步:配置数据库连接
在 .env 文件中配置:
# 主库(写) DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=main_db DB_USERNAME=root DB_PASSWORD=password # 从库(读)- 可配置多个 DB_READ_HOST1=127.0.0.1 DB_READ_HOST2=192.168.1.100 DB_READ_DATABASE=replica_db
第二步:修改 database.php 配置
在 config/database.php 中配置读写分离:
'mysql' => [
'driver' => 'mysql',
// 主库配置(写)
'read' => [
// 从库配置(读)- 可配置多个
[
'host' => env('DB_READ_HOST1', '127.0.0.1'),
'database' => env('DB_READ_DATABASE', 'main_db'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
],
[
'host' => env('DB_READ_HOST2', '127.0.0.1'),
'database' => env('DB_READ_DATABASE', 'main_db'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
],
],
// 写库配置
'write' => [
[
'host' => env('DB_HOST', '127.0.0.1'),
'database' => env('DB_DATABASE', 'main_db'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
],
],
'sticky' => true, // 是否启用粘性连接
'driver' => 'mysql',
'port' => env('DB_PORT', 3306),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
],
使用 DB Facade 手动指定
use Illuminate\Support\Facades\DB;
// 使用默认连接(会根据配置自动选择读写)
$users = DB::table('users')->get(); // 自动使用读库
// 强制使用主库(写)
$users = DB::connection('mysql')->table('users')->get();
// 手动指定使用读库
$users = DB::connection('mysql::read')->table('users')->get();
使用 Eloquent 模型方式
// User.php 模型
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
// 默认使用配置好的读写分离连接
protected $connection = 'mysql';
// 或者为模型指定特定的读写连接
protected $readConnection = 'mysql';
protected $writeConnection = 'mysql';
// 自定义查询方法,强制使用主库
public function scopeFromMaster($query)
{
$query->useWritePdo();
return $query;
}
}
// 使用方式
$users = User::fromMaster()->find(1); // 强制使用主库
$users = User::find(1); // 自动使用读库
高级配置:动态切换
// 创建自定义连接类
namespace App\Support;
use Illuminate\Database\Connection;
use PDO;
class ReadWriteConnection extends Connection
{
public function select($query, $bindings = [], $useReadPdo = true)
{
// 判断是否为写操作
if ($this->isWriteQuery($query)) {
$useReadPdo = false;
}
return parent::select($query, $bindings, $useReadPdo);
}
protected function isWriteQuery($query)
{
$query = trim(preg_replace('/\s+/', ' ', strtolower($query)));
return in_array(substr($query, 0, 6), ['insert', 'update', 'delete', 'create', 'alter', 'drop']);
}
}
中间件方式控制
// 创建读写分离中间件
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\DB;
class ReadWriteMiddleware
{
public function handle($request, Closure $next)
{
// 判断请求类型
if ($request->isMethod('POST') || $request->isMethod('PUT') || $request->isMethod('DELETE')) {
// 写操作强制使用主库
DB::connection('mysql')->statement('USE WRITE');
}
return $next($request);
}
}
事务处理注意事项
use Illuminate\Support\Facades\DB;
// 事务操作必须使用主库
DB::transaction(function () {
// 事务内的所有操作都在主库执行
$user = User::find(1);
$user->name = 'New Name';
$user->save();
// 即使读操作也会在主库执行
$otherUser = User::find(2);
});
// 或者手动指定使用主库
DB::beginTransaction();
try {
$user = User::useWritePdo()->find(1); // 强制使用主库
$user->save();
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
}
负载均衡策略
// 在 config/database.php 中可以配置负载均衡策略
'options' => [
'fetch' => PDO::FETCH_OBJ,
'emulate_prepares' => false,
'driver' => 'mysql',
// 自定义负载均衡算法
],
监控和日志
// 添加事件监听器
namespace App\Providers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
class DatabaseServiceProvider extends ServiceProvider
{
public function boot()
{
// 监听每次查询
DB::listen(function ($query) {
if (app()->environment('local')) {
\Log::info($query->sql, $query->bindings);
}
});
// 可以统计读写分离的使用情况
DB::connection('mysql')->enableQueryLog();
}
}
最佳实践建议:
- 粘性连接(sticky):建议开启,避免同一请求内读写不一致
- 事务处理:事务操作必须在主库执行
- 查询优化:缓存频繁读取但不常变化的数据
- 监控告警:监控主从延迟,设置阈值告警
- 故障转移:配置从库故障时自动使用主库
- 测试环境:确保开发环境有完整的测试用例
// .env 配置示例 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=main_db DB_USERNAME=root DB_PASSWORD=password DB_STICKY=true DB_READ_HOST1=192.168.1.101 DB_READ_HOST2=192.168.1.102 DB_READ_DATABASE=replica_db DB_READ_USERNAME=reader DB_READ_PASSWORD=readpassword
通过以上配置,Laravel 会自动将所有读操作路由到从库,写操作到主库,从而实现读写分离。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播