本文目录导读:

在 Laravel 中实现分库分表,通常有几种主流方案,我会从简单到复杂为你介绍:
基于 Sharding 扩展包
使用 shard-manager 或 laravel-shard
composer require mabasic/laravel-shard
配置示例:
// config/shard.php
return [
'connections' => [
'shard1' => [
'driver' => 'mysql',
'host' => '192.168.1.1',
'database' => 'db_shard_1',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
],
'shard2' => [
'driver' => 'mysql',
'host' => '192.168.1.2',
'database' => 'db_shard_2',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
],
],
'shard_count' => 2,
];
模型使用:
use Mabasic\LaravelShard\Traits\Shardable;
class User extends Model {
use Shardable;
protected $shardKey = 'user_id'; // 分片键
}
手动实现分库分表
Model 基类方式
abstract class ShardModel extends Model {
protected function getShardConnection($key) {
// 根据key计算分库
$database = 'shard_' . ($key % 2);
return $database;
}
protected function getShardTable($key) {
// 根据key计算分表
$table = $this->table . '_' . ($key % 4);
return $table;
}
}
class Order extends ShardModel {
protected $table = 'orders';
public function scopeOnShard($query, $userId) {
$connection = $this->getShardConnection($userId);
$table = $this->getShardTable($userId);
return $query->on($connection)
->from($table);
}
}
使用 Repository 模式
class OrderRepository {
private $connections = ['mysql_shard1', 'mysql_shard2'];
public function save(Order $order, $userId) {
$shard = $userId % count($this->connections);
$table = 'orders_' . ($userId % 4);
$order->setConnection($this->connections[$shard]);
$order->setTable($table);
return $order->save();
}
public function findByUserId($userId) {
$shard = $userId % count($this->connections);
$table = 'orders_' . ($userId % 4);
return Order::on($this->connections[$shard])
->from($table)
->where('user_id', $userId)
->get();
}
}
使用监听器自动切换
// App\Listeners\ShardListener.php
class ShardListener {
public function handle($event) {
// 假设请求头包含分片信息
$shardId = request()->header('X-Shard-ID');
if ($shardId) {
$connection = 'shard_' . ($shardId % 2);
DB::setDefaultConnection($connection);
}
}
}
完整的配置示例
数据库配置
// config/database.php
'connections' => [
'shard_0' => [
'driver' => 'mysql',
'host' => env('DB_HOST_0', '127.0.0.1'),
'port' => env('DB_PORT', 3306),
'database' => env('DB_DATABASE_0', 'shard_0'),
// ... 其他配置
],
'shard_1' => [
'driver' => 'mysql',
'host' => env('DB_HOST_1', '127.0.0.1'),
'port' => env('DB_PORT', 3306),
'database' => env('DB_DATABASE_1', 'shard_1'),
// ... 其他配置
],
],
分片中间件
class ShardMiddleware {
public function handle($request, Closure $next) {
$userId = $request->user()->id;
$shardIndex = $userId % 2;
// 动态设置连接
config(['database.default' => 'shard_' . $shardIndex]);
return $next($request);
}
}
最佳实践建议
- 选择合适的分片键:如用户ID、订单ID等
- 合理设置分片数量:考虑未来扩展性
- 跨分片查询处理:避免跨分片JOIN
- 事务管理:分布式事务处理
- 数据迁移工具:准备数据迁移方案
// 跨分片查询示例
class CrossShardQuery {
public function getOrdersByDate($userId, $startDate, $endDate) {
$orders = collect();
// 如果不知道数据在哪个分片,需要查询所有分片
foreach (['shard_0', 'shard_1'] as $connection) {
$result = Order::on($connection)
->where('user_id', $userId)
->whereBetween('created_at', [$startDate, $endDate])
->get();
$orders = $orders->merge($result);
}
return $orders;
}
}
注意事项
- 索引设计:分片键要有好的索引
- 数据一致性:跨库事务最好使用最终一致性方案
- 监控告警:监控各分片负载
- 备份恢复:按分片进行备份
选择哪种方案取决于你的具体业务需求、数据量和扩展计划,对于小型应用,建议从简单的模型层分库分表开始。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播