laravel 单库分表问题 
                            
                                                    
                        
                    
                    
  
                    
                    关于laravel单库分表
laravel在使用关联关系的时候,对分表支持的并不友好。比如处理hasOne hasMany with等方法都不能使用,而且网上提供的解决方案,都是改造这几个方法,这就涉及到分表的业务代码也需要一定的更改。我有个想法,在laravel最后生成sql语句的时候,发送到mysql执行前,进行拦截,并对其进行重写
举例
1.logs表是根据用户id分表的,表名为logs_1  logs_2
2.那么我业务逻辑中无需修改,按单表使用。只是查询的时候必须加上筛选条件user_id=xx
3.生成的语句是select * from logs where user_id=1;
4.此时只把user_id的值提取到表名上,转换为select * from logs_1; 再发送给mysql执行,那么就解决了laravel分表的问题有点类似于简易版数据库中间件,仅仅是为了解决单库分表,laravel关联关系不好用的问题。
请问这样可行吗?
如果可行,在哪里监听,重写sql呢?
或者,你有啥优雅的方式解决单库分表吗?
ps:一些开源的数据库中间件mycat、dble等,对laravel支持的并不友好,比如不支持子查询等等,业务改造起来很麻烦。
———————————————-实践——————————————–
我发现通过设置模型提供的setTable()方法就可以了。with hasMany等方法都可以使用
1.使用静态方法,给模型设置分表标识
2.重写模型中的getTable()方法
3.使用with等方法调用分表的模型时,先用静态方法设置下表标识,代码如下
namespace App\Contracts\SubTable;
use Illuminate\Database\Eloquent\Model;
abstract class SubTableAbstract extends Model
{
    /**
     * 表名前缀
     */
    public static $prefixTable;
    /**
     * 分表标识
     */
    public static $identity;
    public function getTable()
    {
        return static::$prefixTable . static::$identity;
    }
    /**
     * @inheritdoc
     */
    public static function setTableIdentity(string $identity): void
    {
        static::$identity = $identity;
    }
}要分表的模型继承上述父类,且在模型中设置分表前缀,如
public static $prefixTable = "crm_customers_";使用时,需要先设置分表标识
//假设crms表与crm_customers_xxx是一对多的关系,模型名分别是Crm、CrmCustomer
$user_id='123456';
CrmCustomer::setTableIdentity($user_id);
Crm::query->with('crmCustomers')->first(); 以上初步测试是可以的,不知是否有其他的未知问题? 欢迎评论
以下是查询的方式
- 首先将需要查询的表的分表标识列出来
- 然后拼接各个表查询的sql
- 最后使用union 将各个sql拼接起来,作为一张临时表,这样就可以分页了
$queries = collect();
$userIds = [1,2,3,4,5]
foreach($userIds as $userId){
        $tableName = 'customers_' . $userId;
        $query = DB::table($tableName)
         ->select(['name', 'email', 'phone']);
        // 可以拼接一些查询
        // $query->where('phone','xxxx');
        // 加入集合
        queries->push($$query);
}
// 取出第一个作为查询对象,其他的作为合并对象
$unionQuery = $queries->shift();
$queries->each(function ($item) use ($unionQuery) {
      $unionQuery->unionAll($item);
});
// 设置临时表,执行查询
(new Customer)->setTable('union_customers')->from(DB::raw("({$unionQuery->toSql()}) as union_customers"))
->mergeBindings($unionQuery)
->paginate()可以打印以下最终生成的sql
 
           
         
             
             
             
             
             
             
                     
                     
             
         
         
         
             
             
             
             
             
             
           
           关于 LearnKu
                关于 LearnKu
               
                     
                     
                     粤公网安备 44030502004330号
 粤公网安备 44030502004330号 
 
推荐文章: