如何设计一个业务无感的分库分表组件❓
如下是jdbc的接口,实现有Druid、mybatis等。
| 类/接口 | 作用 | 使用场景 |
|---|---|---|
| DataSource | 连接工厂,管理连接池 | 应用启动时配置,全局使用 |
| Connection | 数据库会话 | 事务管理,创建 Statement |
| Statement | 执行静态SQL | 简单查询(有SQL注入风险) |
| PreparedStatement | 预编译SQL | 参数化查询(安全,推荐) |
| CallableStatement | 调用存储过程 | 执行存储过程 |
| ResultSet | 保存查询结果 | 遍历和处理查询数据 |
正常的流程是:
1️⃣从DataSource中获取Connection
2️⃣从Connection获取各种类型的Statement(传入sql)
3️⃣Statement执行sql
需要在正常的流程上包装一层分库分表的流程,也就是实现ShardDataSource,ShardConnection,ShardPreparedStatement等。
ShardPreparedStatement去执行👇🏻流程:
解析sql → 获取tableName和sql参数 → 得到tableName对应的分库分表规则,将sql参数映射到实际的表和库名 → 生成分表和分库名,改写sql → 到对应的分库上去执行sql。
❓如何到对应分库去执行❓
📢业务中可以记录分库名到原始DataSource(分库)的映射。
❓如何将sql参数➕分表规则映射到对应的分库和分表❓
分表:
下面是分表规则的一个示例:
{
"table_shard_rule": {
"table": "table_name",
"shardCount": 256,
"shardField": "user_id",
"partitionField": "create_time",
"partitionFormat": "yyyy",
"partitionRetentionCount": 3
}
}
执行sql流程❓
匹配rule,table_shard_rule会对应一个原始DataSource(单库),就是说匹配到了这个规则,就会将sql到这个库(DataSource)去执行。
分库
分库的规则同分表。示例如下,分库名为:db1、db_2、db3、db4
{
"db_shard_rule": {
"table": "table_name",
"shardCount": 4,
"shardField": "user_id"
}
}
执行sql流程❓
匹配rule,db_shard_rule会生成sql对应的分库名,table_shard_rule会对应一个原始DataSource map,key是分库名,value是原始DataSource。最终sql会根据分库名找到对应的DataSource,然后去执行sql。
如果当前是单表且有数据,则需要将单表数据迁移到分表上。迁移前需要明确几点:
在发版前需要尽量的迁移现有数据,需要做的工作有:
发版的代码开启双写,也就是说,对单表的更新和对分表的更新放在一个事务中,并且通过开关控制读单表数据(因为尚未发版的节点还是写单表),当全部节点发布结束后,然后切换开关读分表数据,最后关闭双写。