分库分表的实现方案,一般分为两种
1、增加一个中间层,中间层实现 MySQL 客户端协议,可以做到应用程序无感知地与中间层交互。由于是基于协议层的代理,可以做到支持多语言,但需要多启动一个进程、SQL 的解析也耗费大量性能、由于协议绑定仅支持单个种类的数据库库。
2、在代码层面增加一个路由程序,控制对数据库与表的读写。路由程序写在项目里,与编程语言绑定、连接数高、但相对轻量(比如 Java 仅需要引入 SharingShpere 组件中 Sharding-JDBC 的 jar 即可)、支持任意数据库。
代码怎么写?怎么配?
以 Sharding-JDBC 实现分库分表为例子
1、数据库环境
ds0:172.31.32.184
ds1:172.31.32.234
用作分库
2、在 ds0 和 ds1 库中建表,t_order0 和 t_order1 用做分表
create table t_order0(
order_id int primary key,
user_id int,
goods_id int,
goods_name varchar(200)
);
create table t_order1(
order_id int primary key,
user_id int,
goods_id int,
goods_name varchar(200)
);
3、新建 maven 项目,添加依赖
org.apache.shardingsphere
sharding-jdbc-core
4.1.1
com.zaxxer
HikariCP
3.4.5
mysql
mysql-connector-java
8.0.21
4、数据源连接工具类,使用 HikariCP 数据库连接池
package constxiong;
import com.zaxxer.hikari.HikariDataSource;
/**
* 获取 DataSource 工具类,使用了 Hikari 数据库连接池
*/
import javax.sql.DataSource;
public final class DataSourceUtil {
private static final int PORT = 3306;
/**
* 通过 Hikari 数据库连接池创建 DataSource
* @param ip
* @param username
* @param password
* @param dataSourceName
* @return
*/
public static DataSource createDataSource(String ip, String username, String password, String dataSourceName) {
HikariDataSource result = new HikariDataSource();
result.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
result.setJdbcUrl(String.format("jdbc:mysql://%s:%s/%s?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", ip, PORT, dataSourceName));
result.setUsername(username);
result.setPassword(password);
return result;
}
}
5、测试代码
测试逻辑:
package constxiong;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* 测试 ShardingSphere 分表分库
*/
public class Test {
//DataSource 0
private static DataSource ds0 = DataSourceUtil.createDataSource("172.31.32.234", "root", "constxiong@123", "constxiong");
// DataSource 1
private static DataSource ds1 = DataSourceUtil.createDataSource("172.31.32.184", "root", "constxiong@123", "constxiong");
public static void main(String[] args) throws SQLException {
// 配置真实数据源
Map dataSourceMap = new HashMap<>();
dataSourceMap.put("ds0", ds0);
dataSourceMap.put("ds1", ds1);
// 配置Order表规则
TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration("t_order", "ds$->{0..1}.t_order$->{0..1}");
// 配置分库 + 分表策略
orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds${user_id % 2}"));
orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order${order_id % 2}"));
// 配置分片规则
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);
// 获取数据源对象
DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, new Properties());
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement();
statement.execute("insert into t_order value(1, 1, 1, '电视机')");
statement.execute("insert into t_order value(2, 1, 2, '可乐')");
statement.execute("insert into t_order value(3, 2, 8, '空调')");
statement.execute("insert into t_order value(4, 2, 9, '手机壳')");
statement.execute("select * from t_order where user_id = 2");
ResultSet resultSet = statement.getResultSet();
while (resultSet.next()) {
System.out.printf("user_id:%d, order_id:%d, goods_id:%d, goods_name:%s\n",
resultSet.getInt("user_id"),
resultSet.getInt("order_id"),
resultSet.getInt("goods_id"),
resultSet.getString("goods_name")
);
}
}
}
6、结果
数据按照分库分表的规则插入对应的数据库与表中
user_id = 2 数据代码查询
user_id:2, order_id:4, goods_id:9, goods_name:手机壳
user_id:2, order_id:3, goods_id:8, goods_name:空调