按 Enter 键跳转到正文

MySQL分库分表(无中间件)

MySQL分库分表(无中间件)

一、 分库分表方案设计

1. 垂直拆分 (按业务模块)

 1-- 原始单体数据库
 2CREATE DATABASE ecommerce;
 3USE ecommerce;
 4
 5-- 垂直拆分后的数据库
 6-- 用户库
 7CREATE DATABASE user_center;
 8USE user_center;
 9
10CREATE TABLE users (
11    user_id BIGINT PRIMARY KEY,
12    username VARCHAR(50) UNIQUE,
13    email VARCHAR(100) UNIQUE,
14    password VARCHAR(100),
15    mobile VARCHAR(20),
16    status TINYINT DEFAULT 1,
17    created_at DATETIME,
18    updated_at DATETIME
19);
20
21CREATE TABLE user_profiles (
22    user_id BIGINT PRIMARY KEY,
23    real_name VARCHAR(50),
24    avatar VARCHAR(200),
25    gender TINYINT,
26    birthday DATE,
27    bio TEXT
28);
29
30CREATE TABLE user_address (
31    address_id BIGINT PRIMARY KEY,
32    user_id BIGINT,
33    province VARCHAR(50),
34    city VARCHAR(50),
35    district VARCHAR(50),
36    detail VARCHAR(200),
37    is_default TINYINT DEFAULT 0,
38    INDEX idx_user_id (user_id)
39);
40
41-- 订单库
42CREATE DATABASE order_center;
43USE order_center;
44
45CREATE TABLE orders (
46    order_id BIGINT PRIMARY KEY,
47    user_id BIGINT,
48    total_amount DECIMAL(10,2),
49    status TINYINT,
50    payment_status TINYINT,
51    created_at DATETIME,
52    paid_at DATETIME
53);
54
55CREATE TABLE order_items (
56    item_id BIGINT PRIMARY KEY,
57    order_id BIGINT,
58    product_id BIGINT,
59    product_name VARCHAR(100),
60    price DECIMAL(10,2),
61    quantity INT,
62    INDEX idx_order_id (order_id)
63);
64
65-- 商品库
66CREATE DATABASE product_center;
67USE product_center;
68
69CREATE TABLE products (
70    product_id BIGINT PRIMARY KEY,
71    name VARCHAR(100),
72    category_id INT,
73    price DECIMAL(10,2),
74    stock INT,
75    status TINYINT,
76    created_at DATETIME
77);
78
79CREATE TABLE categories (
80    category_id INT PRIMARY KEY,
81    name VARCHAR(50),
82    parent_id INT
83);

2. 水平拆分 (按数据量)

用户表水平分表(10个分表)

 1-- 在 user_center 数据库中创建分表
 2USE user_center;
 3
 4-- 下面语句中的//为分隔符
 5DELIMITER //
 6CREATE PROCEDURE CreateUserShards()
 7BEGIN
 8    DECLARE i INT DEFAULT 0;
 9    WHILE i < 10 DO
10        SET @sql = CONCAT('
11            CREATE TABLE users_', i, ' (
12                user_id BIGINT PRIMARY KEY,
13                username VARCHAR(50) NOT NULL,
14                email VARCHAR(100),
15                password VARCHAR(100),
16                mobile VARCHAR(20),
17                status TINYINT DEFAULT 1,
18                created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
19                updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
20                UNIQUE KEY uk_username_', i, ' (username),
21                UNIQUE KEY uk_email_', i, ' (email),
22                INDEX idx_mobile_', i, ' (mobile),
23                INDEX idx_created_', i, ' (created_at)
24            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
25        ');
26        PREPARE stmt FROM @sql;
27        EXECUTE stmt;
28        DEALLOCATE PREPARE stmt;
29        SET i = i + 1;
30    END WHILE;
31END//
32DELIMITER ;
33
34CALL CreateUserShards();

订单表水平分表(按用户ID分表)

 1USE order_center;
 2
 3DELIMITER //
 4CREATE PROCEDURE CreateOrderShards()
 5BEGIN
 6    DECLARE i INT DEFAULT 0;
 7    WHILE i < 10 DO
 8        SET @sql = CONCAT('
 9            CREATE TABLE orders_', i, ' (
10                order_id BIGINT PRIMARY KEY,
11                user_id BIGINT NOT NULL,
12                total_amount DECIMAL(10,2),
13                status TINYINT DEFAULT 1,
14                payment_status TINYINT DEFAULT 0,
15                created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
16                paid_at DATETIME,
17                INDEX idx_user_id_', i, ' (user_id),
18                INDEX idx_created_', i, ' (created_at),
19                INDEX idx_status_', i, ' (status)
20            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
21        ');
22        PREPARE stmt FROM @sql;
23        EXECUTE stmt;
24        DEALLOCATE PREPARE stmt;
25        
26        -- 创建对应的订单项分表
27        SET @sql = CONCAT('
28            CREATE TABLE order_items_', i, ' (
29                item_id BIGINT PRIMARY KEY,
30                order_id BIGINT NOT NULL,
31                product_id BIGINT,
32                product_name VARCHAR(100),
33                price DECIMAL(10,2),
34                quantity INT,
35                INDEX idx_order_id_', i, ' (order_id),
36                INDEX idx_product_id_', i, ' (product_id)
37            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
38        ');
39        PREPARE stmt FROM @sql;
40        EXECUTE stmt;
41        DEALLOCATE PREPARE stmt;
42        
43        SET i = i + 1;
44    END WHILE;
45END//
46DELIMITER ;
47
48CALL CreateOrderShards();

二、程序中处理(PHP)

1. 基础配置类

 1<?php
 2// Config.php
 3class Config {
 4    private static $instance;
 5    private $config;
 6    
 7    private function __construct() {
 8        $this->config = [
 9            'databases' => [
10                'user_center' => [
11                    'host' => 'localhost',
12                    'port' => 3306,
13                    'username' => 'root',
14                    'password' => 'password',
15                    'dbname' => 'user_center'
16                ],
17                'order_center' => [
18                    'host' => 'localhost',
19                    'port' => 3306,
20                    'username' => 'root',
21                    'password' => 'password',
22                    'dbname' => 'order_center'
23                ],
24                'product_center' => [
25                    'host' => 'localhost',
26                    'port' => 3306,
27                    'username' => 'root',
28                    'password' => 'password',
29                    'dbname' => 'product_center'
30                ]
31            ],
32            'shard' => [
33                'user' => 10,     // 用户表10个分片
34                'order' => 10     // 订单表10个分片
35            ]
36        ];
37    }
38    
39    public static function getInstance() {
40        if (!self::$instance) {
41            self::$instance = new self();
42        }
43        return self::$instance;
44    }
45    
46    public function get($key) {
47        $keys = explode('.', $key);
48        $value = $this->config;
49        
50        foreach ($keys as $k) {
51            if (!isset($value[$k])) {
52                return null;
53            }
54            $value = $value[$k];
55        }
56        
57        return $value;
58    }
59}

2. 分片路由类

 1<?php
 2// ShardRouter.php
 3class ShardRouter {
 4    private $shardConfig;
 5    
 6    public function __construct() {
 7        $config = Config::getInstance();
 8        $this->shardConfig = $config->get('shard');
 9    }
10    
11    /**
12     * 根据用户ID计算分片
13     */
14    public function getUserShard($userId) {
15        return $userId % $this->shardConfig['user'];
16    }
17    
18    /**
19     * 根据订单ID计算分片(订单按用户ID分片)
20     */
21    public function getOrderShard($orderId) {
22        // 假设订单ID包含用户ID信息
23        $userId = $this->extractUserIdFromOrderId($orderId);
24        return $userId % $this->shardConfig['order'];
25    }
26    
27    /**
28     * 根据用户名计算分片(用于登录查询)
29     */
30    public function getShardByString($str, $type = 'user') {
31        $shardCount = $this->shardConfig[$type];
32        return crc32($str) % $shardCount;
33    }
34    
35    /**
36     * 生成分布式ID(雪花算法)
37     */
38    public function generateId($shardId = 0, $timestamp = null) {
39        $timestamp = $timestamp ?? (int)(microtime(true) * 1000);
40        $workerId = $shardId % 1024;
41        $sequence = mt_rand(0, 4095);
42        
43        return (($timestamp - 1577836800000) << 22) 
44             | ($workerId << 12) 
45             | $sequence;
46    }
47    
48    /**
49     * 从订单ID提取用户ID(根据业务规则)
50     */
51    private function extractUserIdFromOrderId($orderId) {
52        // 实际业务中需要根据ID生成规则来解析
53        // 这里简单返回订单ID的低位部分作为用户ID
54        return $orderId & 0x3FFFFFFF;
55    }
56    
57    /**
58     * 获取表名
59     */
60    public function getTableName($baseTable, $shardId) {
61        return $baseTable . '_' . $shardId;
62    }
63}

3. 数据库连接管理

 1<?php
 2// DatabaseManager.php
 3class DatabaseManager {
 4    private static $instance;
 5    private $connections = [];
 6    private $config;
 7    
 8    private function __construct() {
 9        $this->config = Config::getInstance();
10    }
11    
12    public static function getInstance() {
13        if (!self::$instance) {
14            self::$instance = new self();
15        }
16        return self::$instance;
17    }
18    
19    /**
20     * 获取数据库连接
21     */
22    public function getConnection($database, $shardId = null) {
23        $key = $database . ($shardId !== null ? '_' . $shardId : '');
24        
25        if (!isset($this->connections[$key])) {
26            $dbConfig = $this->config->get("databases.{$database}");
27            
28            if (!$dbConfig) {
29                throw new Exception("Database config not found: {$database}");
30            }
31            
32            try {
33                $dsn = "mysql:host={$dbConfig['host']};port={$dbConfig['port']};dbname={$dbConfig['dbname']};charset=utf8mb4";
34                
35                $this->connections[$key] = new PDO(
36                    $dsn,
37                    $dbConfig['username'],
38                    $dbConfig['password'],
39                    [
40                        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
41                        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
42                        PDO::ATTR_EMULATE_PREPARES => false,
43                        PDO::ATTR_PERSISTENT => false
44                    ]
45                );
46            } catch (PDOException $e) {
47                throw new Exception("Database connection failed: " . $e->getMessage());
48            }
49        }
50        
51        return $this->connections[$key];
52    }
53    
54    /**
55     * 开始事务(单分片事务)
56     */
57    public function beginTransaction($database, $shardId = null) {
58        $connection = $this->getConnection($database, $shardId);
59        return $connection->beginTransaction();
60    }
61    
62    /**
63     * 提交事务
64     */
65    public function commit($database, $shardId = null) {
66        $connection = $this->getConnection($database, $shardId);
67        return $connection->commit();
68    }
69    
70    /**
71     * 回滚事务
72     */
73    public function rollback($database, $shardId = null) {
74        $connection = $this->getConnection($database, $shardId);
75        return $connection->rollback();
76    }
77}

4. 用户服务类示例(完整CRUD)

  1<?php
  2// UserService.php
  3class UserService {
  4    private $db;
  5    private $router;
  6    
  7    public function __construct() {
  8        $this->db = DatabaseManager::getInstance();
  9        $this->router = new ShardRouter();
 10    }
 11    
 12    /**
 13     * 创建用户(写入操作)
 14     */
 15    public function createUser($userData) {
 16        // 生成用户ID
 17        $userId = $this->router->generateId();
 18        $shardId = $this->router->getUserShard($userId);
 19        
 20        $tableName = $this->router->getTableName('users', $shardId);
 21        $connection = $this->db->getConnection('user_center', $shardId);
 22        
 23        try {
 24            // 开始事务
 25            $this->db->beginTransaction('user_center', $shardId);
 26            
 27            // 插入用户基础信息
 28            $sql = "INSERT INTO {$tableName} 
 29                    (user_id, username, email, password, mobile, created_at) 
 30                    VALUES (?, ?, ?, ?, ?, NOW())";
 31            
 32            $stmt = $connection->prepare($sql);
 33            $stmt->execute([
 34                $userId,
 35                $userData['username'],
 36                $userData['email'],
 37                password_hash($userData['password'], PASSWORD_DEFAULT),
 38                $userData['mobile'] ?? null
 39            ]);
 40            
 41            // 插入用户档案(垂直分库,但在同一个事务中)
 42            $this->createUserProfile($userId, $userData);
 43            
 44            // 提交事务
 45            $this->db->commit('user_center', $shardId);
 46            
 47            return $userId;
 48            
 49        } catch (Exception $e) {
 50            $this->db->rollback('user_center', $shardId);
 51            throw new Exception("创建用户失败: " . $e->getMessage());
 52        }
 53    }
 54    
 55    /**
 56     * 更新用户信息
 57     */
 58    public function updateUser($userId, $updateData) {
 59        $shardId = $this->router->getUserShard($userId);
 60        $tableName = $this->router->getTableName('users', $shardId);
 61        $connection = $this->db->getConnection('user_center', $shardId);
 62        
 63        $allowedFields = ['email', 'mobile', 'password'];
 64        $setParts = [];
 65        $params = [];
 66        
 67        foreach ($updateData as $field => $value) {
 68            if (in_array($field, $allowedFields)) {
 69                if ($field === 'password') {
 70                    $value = password_hash($value, PASSWORD_DEFAULT);
 71                }
 72                $setParts[] = "{$field} = ?";
 73                $params[] = $value;
 74            }
 75        }
 76        
 77        if (empty($setParts)) {
 78            throw new Exception("没有有效的更新字段");
 79        }
 80        
 81        $params[] = $userId;
 82        
 83        $sql = "UPDATE {$tableName} SET " . implode(', ', $setParts) . " WHERE user_id = ?";
 84        $stmt = $connection->prepare($sql);
 85        
 86        return $stmt->execute($params);
 87    }
 88    
 89    /**
 90     * 根据用户ID查询(精确查询)
 91     */
 92    public function getUserById($userId) {
 93        $shardId = $this->router->getUserShard($userId);
 94        $tableName = $this->router->getTableName('users', $shardId);
 95        $connection = $this->db->getConnection('user_center', $shardId);
 96        
 97        $sql = "SELECT * FROM {$tableName} WHERE user_id = ?";
 98        $stmt = $connection->prepare($sql);
 99        $stmt->execute([$userId]);
100        
101        $user = $stmt->fetch();
102        if ($user) {
103            $user['profile'] = $this->getUserProfile($userId);
104            $user['addresses'] = $this->getUserAddresses($userId);
105        }
106        
107        return $user;
108    }
109    
110    /**
111     * 根据用户名查询(需要计算分片)
112     */
113    public function getUserByUsername($username) {
114        $shardId = $this->router->getShardByString($username, 'user');
115        $tableName = $this->router->getTableName('users', $shardId);
116        $connection = $this->db->getConnection('user_center', $shardId);
117        
118        $sql = "SELECT * FROM {$tableName} WHERE username = ?";
119        $stmt = $connection->prepare($sql);
120        $stmt->execute([$username]);
121        
122        return $stmt->fetch();
123    }
124    
125    /**
126     * 批量查询用户信息
127     */
128    public function getUsersByIds($userIds) {
129        $usersByShard = [];
130        
131        // 按分片分组用户ID
132        foreach ($userIds as $userId) {
133            $shardId = $this->router->getUserShard($userId);
134            $usersByShard[$shardId][] = $userId;
135        }
136        
137        $results = [];
138        foreach ($usersByShard as $shardId => $shardUserIds) {
139            $tableName = $this->router->getTableName('users', $shardId);
140            $connection = $this->db->getConnection('user_center', $shardId);
141            
142            $placeholders = str_repeat('?,', count($shardUserIds) - 1) . '?';
143            $sql = "SELECT * FROM {$tableName} WHERE user_id IN ({$placeholders})";
144            
145            $stmt = $connection->prepare($sql);
146            $stmt->execute($shardUserIds);
147            
148            $results = array_merge($results, $stmt->fetchAll());
149        }
150        
151        return $results;
152    }
153    
154    /**
155     * 复杂查询:按条件搜索用户(需要遍历分片)
156     */
157    public function searchUsers($conditions, $page = 1, $pageSize = 20) {
158        $allUsers = [];
159        $shardCount = Config::getInstance()->get('shard.user');
160        
161        for ($shardId = 0; $shardId < $shardCount; $shardId++) {
162            $tableName = $this->router->getTableName('users', $shardId);
163            $connection = $this->db->getConnection('user_center', $shardId);
164            
165            $where = [];
166            $params = [];
167            
168            if (!empty($conditions['username'])) {
169                $where[] = "username LIKE ?";
170                $params[] = $conditions['username'] . '%';
171            }
172            
173            if (!empty($conditions['email'])) {
174                $where[] = "email LIKE ?";
175                $params[] = $conditions['email'] . '%';
176            }
177            
178            if (!empty($conditions['mobile'])) {
179                $where[] = "mobile LIKE ?";
180                $params[] = $conditions['mobile'] . '%';
181            }
182            
183            $whereClause = $where ? "WHERE " . implode(' AND ', $where) : "";
184            $offset = ($page - 1) * $pageSize;
185            
186            $sql = "SELECT * FROM {$tableName} {$whereClause} LIMIT ? OFFSET ?";
187            $params[] = $pageSize;
188            $params[] = $offset;
189            
190            $stmt = $connection->prepare($sql);
191            $stmt->execute($params);
192            
193            $shardUsers = $stmt->fetchAll();
194            $allUsers = array_merge($allUsers, $shardUsers);
195        }
196        
197        // 在PHP中进行排序和分页
198        usort($allUsers, function($a, $b) {
199            return strcmp($b['created_at'], $a['created_at']);
200        });
201        
202        return array_slice($allUsers, 0, $pageSize);
203    }
204    
205    /**
206     * 删除用户
207     */
208    public function deleteUser($userId) {
209        $shardId = $this->router->getUserShard($userId);
210        $tableName = $this->router->getTableName('users', $shardId);
211        $connection = $this->db->getConnection('user_center', $shardId);
212        
213        try {
214            $this->db->beginTransaction('user_center', $shardId);
215            
216            // 删除用户基础信息
217            $sql = "DELETE FROM {$tableName} WHERE user_id = ?";
218            $stmt = $connection->prepare($sql);
219            $stmt->execute([$userId]);
220            
221            // 删除关联数据
222            $this->deleteUserProfile($userId);
223            $this->deleteUserAddresses($userId);
224            
225            $this->db->commit('user_center', $shardId);
226            return true;
227            
228        } catch (Exception $e) {
229            $this->db->rollback('user_center', $shardId);
230            throw new Exception("删除用户失败: " . $e->getMessage());
231        }
232    }
233    
234    // 用户档案相关方法
235    private function createUserProfile($userId, $userData) {
236        $connection = $this->db->getConnection('user_center');
237        
238        $sql = "INSERT INTO user_profiles 
239                (user_id, real_name, avatar, gender, birthday, bio) 
240                VALUES (?, ?, ?, ?, ?, ?)";
241        
242        $stmt = $connection->prepare($sql);
243        return $stmt->execute([
244            $userId,
245            $userData['real_name'] ?? '',
246            $userData['avatar'] ?? '',
247            $userData['gender'] ?? 0,
248            $userData['birthday'] ?? null,
249            $userData['bio'] ?? ''
250        ]);
251    }
252    
253    private function getUserProfile($userId) {
254        $connection = $this->db->getConnection('user_center');
255        
256        $sql = "SELECT * FROM user_profiles WHERE user_id = ?";
257        $stmt = $connection->prepare($sql);
258        $stmt->execute([$userId]);
259        
260        return $stmt->fetch();
261    }
262    
263    private function getUserAddresses($userId) {
264        $connection = $this->db->getConnection('user_center');
265        
266        $sql = "SELECT * FROM user_address WHERE user_id = ? ORDER BY is_default DESC";
267        $stmt = $connection->prepare($sql);
268        $stmt->execute([$userId]);
269        
270        return $stmt->fetchAll();
271    }
272    
273    private function deleteUserProfile($userId) {
274        $connection = $this->db->getConnection('user_center');
275        
276        $sql = "DELETE FROM user_profiles WHERE user_id = ?";
277        $stmt = $connection->prepare($sql);
278        return $stmt->execute([$userId]);
279    }
280    
281    private function deleteUserAddresses($userId) {
282        $connection = $this->db->getConnection('user_center');
283        
284        $sql = "DELETE FROM user_address WHERE user_id = ?";
285        $stmt = $connection->prepare($sql);
286        return $stmt->execute([$userId]);
287    }
288}

5. 订单服务类示例

  1<?php
  2// OrderService.php
  3class OrderService {
  4    private $db;
  5    private $router;
  6    
  7    public function __construct() {
  8        $this->db = DatabaseManager::getInstance();
  9        $this->router = new ShardRouter();
 10    }
 11    
 12    /**
 13     * 创建订单
 14     */
 15    public function createOrder($orderData) {
 16        $userId = $orderData['user_id'];
 17        $shardId = $this->router->getUserShard($userId);
 18        
 19        $orderId = $this->router->generateId($shardId);
 20        $orderTable = $this->router->getTableName('orders', $shardId);
 21        $itemTable = $this->router->getTableName('order_items', $shardId);
 22        $connection = $this->db->getConnection('order_center', $shardId);
 23        
 24        try {
 25            $this->db->beginTransaction('order_center', $shardId);
 26            
 27            // 插入订单主表
 28            $sql = "INSERT INTO {$orderTable} 
 29                    (order_id, user_id, total_amount, status, payment_status, created_at) 
 30                    VALUES (?, ?, ?, 1, 0, NOW())";
 31            
 32            $stmt = $connection->prepare($sql);
 33            $stmt->execute([
 34                $orderId,
 35                $userId,
 36                $orderData['total_amount']
 37            ]);
 38            
 39            // 插入订单项
 40            foreach ($orderData['items'] as $item) {
 41                $itemId = $this->router->generateId($shardId);
 42                
 43                $sql = "INSERT INTO {$itemTable} 
 44                        (item_id, order_id, product_id, product_name, price, quantity) 
 45                        VALUES (?, ?, ?, ?, ?, ?)";
 46                
 47                $stmt = $connection->prepare($sql);
 48                $stmt->execute([
 49                    $itemId,
 50                    $orderId,
 51                    $item['product_id'],
 52                    $item['product_name'],
 53                    $item['price'],
 54                    $item['quantity']
 55                ]);
 56            }
 57            
 58            $this->db->commit('order_center', $shardId);
 59            return $orderId;
 60            
 61        } catch (Exception $e) {
 62            $this->db->rollback('order_center', $shardId);
 63            throw new Exception("创建订单失败: " . $e->getMessage());
 64        }
 65    }
 66    
 67    /**
 68     * 更新订单状态
 69     */
 70    public function updateOrderStatus($orderId, $status) {
 71        $shardId = $this->router->getOrderShard($orderId);
 72        $tableName = $this->router->getTableName('orders', $shardId);
 73        $connection = $this->db->getConnection('order_center', $shardId);
 74        
 75        $sql = "UPDATE {$tableName} SET status = ?, updated_at = NOW() WHERE order_id = ?";
 76        $stmt = $connection->prepare($sql);
 77        
 78        return $stmt->execute([$status, $orderId]);
 79    }
 80    
 81    /**
 82     * 根据订单ID查询
 83     */
 84    public function getOrderById($orderId) {
 85        $shardId = $this->router->getOrderShard($orderId);
 86        $orderTable = $this->router->getTableName('orders', $shardId);
 87        $itemTable = $this->router->getTableName('order_items', $shardId);
 88        $connection = $this->db->getConnection('order_center', $shardId);
 89        
 90        // 查询订单基本信息
 91        $sql = "SELECT * FROM {$orderTable} WHERE order_id = ?";
 92        $stmt = $connection->prepare($sql);
 93        $stmt->execute([$orderId]);
 94        
 95        $order = $stmt->fetch();
 96        if ($order) {
 97            // 查询订单项
 98            $sql = "SELECT * FROM {$itemTable} WHERE order_id = ?";
 99            $stmt = $connection->prepare($sql);
100            $stmt->execute([$orderId]);
101            $order['items'] = $stmt->fetchAll();
102        }
103        
104        return $order;
105    }
106    
107    /**
108     * 查询用户订单列表
109     */
110    public function getUserOrders($userId, $page = 1, $pageSize = 20) {
111        $shardId = $this->router->getUserShard($userId);
112        $tableName = $this->router->getTableName('orders', $shardId);
113        $connection = $this->db->getConnection('order_center', $shardId);
114        
115        $offset = ($page - 1) * $pageSize;
116        
117        $sql = "SELECT * FROM {$tableName} 
118                WHERE user_id = ? 
119                ORDER BY created_at DESC 
120                LIMIT ? OFFSET ?";
121        
122        $stmt = $connection->prepare($sql);
123        $stmt->execute([$userId, $pageSize, $offset]);
124        
125        return $stmt->fetchAll();
126    }
127}

6. 使用示例

6.1 用户注册和订单创建

 1<?php
 2// register_and_order.php
 3require_once 'Config.php';
 4require_once 'ShardRouter.php';
 5require_once 'DatabaseManager.php';
 6require_once 'UserService.php';
 7require_once 'OrderService.php';
 8
 9try {
10    // 初始化服务
11    $userService = new UserService();
12    $orderService = new OrderService();
13    
14    // 1. 创建用户
15    $userData = [
16        'username' => 'zhangsan',
17        'email' => 'zhangsan@example.com',
18        'password' => '123456',
19        'mobile' => '13800138000',
20        'real_name' => '张三',
21        'avatar' => 'avatar.jpg'
22    ];
23    
24    $userId = $userService->createUser($userData);
25    echo "用户创建成功,ID: {$userId}\n";
26    
27    // 2. 为用户创建订单
28    $orderData = [
29        'user_id' => $userId,
30        'total_amount' => 299.00,
31        'items' => [
32            [
33                'product_id' => 1001,
34                'product_name' => 'iPhone 14',
35                'price' => 299.00,
36                'quantity' => 1
37            ]
38        ]
39    ];
40    
41    $orderId = $orderService->createOrder($orderData);
42    echo "订单创建成功,ID: {$orderId}\n";
43    
44    // 3. 查询用户信息
45    $user = $userService->getUserById($userId);
46    echo "用户信息: " . json_encode($user, JSON_UNESCAPED_UNICODE) . "\n";
47    
48    // 4. 查询订单信息
49    $order = $orderService->getOrderById($orderId);
50    echo "订单信息: " . json_encode($order, JSON_UNESCAPED_UNICODE) . "\n";
51    
52    // 5. 查询用户订单列表
53    $orders = $orderService->getUserOrders($userId);
54    echo "用户订单数量: " . count($orders) . "\n";
55    
56} catch (Exception $e) {
57    echo "操作失败: " . $e->getMessage() . "\n";
58}

6.2 批量操作示例

 1<?php
 2// batch_operations.php
 3require_once 'UserService.php';
 4
 5$userService = new UserService();
 6
 7// 批量查询用户信息
 8$userIds = [123456, 234567, 345678, 456789];
 9$users = $userService->getUsersByIds($userIds);
10echo "批量查询到 " . count($users) . " 个用户\n";
11
12// 复杂搜索
13$conditions = [
14    'username' => 'zhang',
15    'mobile' => '138'
16];
17$users = $userService->searchUsers($conditions, 1, 10);
18echo "搜索到 " . count($users) . " 个用户\n";
19
20// 更新用户信息
21$updateResult = $userService->updateUser(123456, [
22    'email' => 'new_email@example.com',
23    'mobile' => '13900139000'
24]);
25echo "更新结果: " . ($updateResult ? '成功' : '失败') . "\n";

三、 总结

写入操作:

  • 先计算分片:根据分片键(如用户ID)计算目标分片

  • 获取对应连接:连接到正确的数据库和分表

  • 执行写入:在目标分片上执行INSERT/UPDATE

  • 事务管理:同一分片内的事务可以保证一致性

查询操作:

  • 精确查询:通过分片键直接定位到具体分片

  • 批量查询:按分片分组,分别查询后合并结果

  • 复杂查询:遍历所有分片,在PHP层进行结果聚合

  • 跨库查询:避免跨分片JOIN,通过多次查询在应用层组装

更新操作:

  • 定位分片:通过分片键找到数据所在分片

  • 单分片更新:在单个分片内完成更新

  • 批量更新:按分片分组执行

删除操作:

  • 定位分片:找到数据所在分片

  • 事务处理:删除主表和关联表数据

  • 级联删除:在应用层处理关联数据删除

说明

这种方案虽然增加了应用层的复杂性,但避免了中间件的依赖,提供了更大的灵活性。

在实际应用中,还需要考虑连接池、缓存、监控等配套措施。

发表评论