ThinkPHP6 业务分表之五:优化

看前四篇的代码,会发现很多固定值,每次都要重新写一遍,如果存在修改或者新人加入,就容易造成一些难维护,所以对一些常用的操作进行一个封装,因为我也没实际业务使用过分表,可能一些东西就没考虑到。

app/util/Subtable.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?php
declare (strict_types = 1);

namespace app\util;

use think\facade\Db;

class Subtable {
/**
* 支持分表的列表
* 格式按照 表前缀 -> 分表数,生成会按照 `_` 来拼接
*
* @var array
*/
private static $tables = [
'users' => 16,
'order' => 32,
];

/*
* 获取指定表的 Db 实例
*
* @param string $name 名称
* @param int $uid UID
* @return \think\facade\Db
*/
public static function db(string $name, ?int $uid = null): Db
{
return Db::table(self::name($name, $uid));
}

/*
* 获取指定表的名称
*
* @param string $name 名称
* @param int $uid UID
* @return string
*/
public static function name(string $name, ?int $uid = null): string
{
$index = self::index($name, $uid);

return sprintf('%s_%s', $name, $index);
}

/*
* 获取指定表的 ID(十六进制)
*
* @param string $name 名称
* @param int $uid UID
* @return string
*/
public static function index(string $name, ?int $uid = null) :string
{
if(is_null($uid)) {
// 这里需要替换成获取 UID 的方法
throw new \Exception('UID 值异常');
}

if(!isset(self::$tables[$name])) {
throw new \Exception(sprintf('不支持当前 %s 表', $name));
}

if((int) $uid === 0) {
throw new \Exception('UID 值异常');
}

return sprintf('%x', $uid % self::$tables[$name]);
}

/*
* 获取指定表的分表数
*
* @param string $name 名称
* @return int
*/
public static function number(string $name) :int
{
if(!isset(self::$tables[$name])) {
throw new \Exception(sprintf('不支持当前 %s 表', $name));
}

return (int) self::$tables[$name];
}

/*
* UNION 生成
*
* @param string $name 名称
* @param string $field 查询字段
* @param string $other 其他条件,比如 where
* @param bool $has_all 是否使用 UNION ALL
* @return string
*/
public static function union(string $name, string $field = '*', string $other = '', ?bool $has_all = true) :string
{
$number = self::number($name);

$sql = '';

for($i = 0; $i < $number; $i++) {
if($i !== 0) {
$sql .= $has_all ? ' UNION ALL ' : ' UNION ';
}

$sql .= sprintf('SELECT %s FROM %s_%x %s', $field, $name, $i, $other);
}

return $sql;
}
}
往上