Sharding-JDBC 简介
Sharding-JDBC直接封装JDBC API,可以理解为增强版的JDBC驱动,旧代码迁移成本:
- 可适用于任何基于Java的ORM框架,如:JPA、HIbernate、MYbatis、Spring JDBC Template或者直接使用JDBC。
- 可基于任何第三方的数据库连接池,如:DBCP、C3P0、Druid等。
- 理论上可支持任意实现JDBC规范的数据库。目前支持MySQL、Oracle、SQLServer等。
Sharding-JDBC定位为轻量级Java框架,使用客户端直连数据库,以jar包形式提供服务,未使用中间层,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式。采用“半理解”理念的SQL解析引擎,以达到性能与兼容性的最大平衡。
Sharding-JDBC功能灵活且全面:
- 分片策略灵活,可支持 = , BETWEEN,IN等多维度分片,也支持多分片键共用。
- SQL解析功能完善,支持聚合,分组,排序,Limit,TOP等查询,并且支持Binding Table以及笛卡尔积的表查询。
- 支持柔性事务(目前仅最大努力送达型)。
- 支持读写分离。
- 支持分布式生成全局主键。
整体架构图


sharding-JDBC 实现分表
数据库表
CREATE TABLE IF NOT EXISTS `t_order_0` ( `order_id` INT NOT NULL, `user_id` INT NOT NULL, PRIMARY KEY (`order_id`) ); CREATE TABLE IF NOT EXISTS `t_order_1` ( `order_id` INT NOT NULL, `user_id` INT NOT NULL, PRIMARY KEY (`order_id`) ); CREATE TABLE IF NOT EXISTS `t_order_2` ( `order_id` INT NOT NULL, `user_id` INT NOT NULL, PRIMARY KEY (`order_id`) );
pom.xml
<dependency> <groupId>com.dangdang</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>1.4.2</version> </dependency> <dependency> <groupId>com.dangdang</groupId> <artifactId>sharding-jdbc-config-spring</artifactId> <version>1.4.0</version> </dependency>
Spring配置
<rdb:strategy id="tableShardingStrategy" sharding-columns="user_id" algorithm-expression="t_order_${user_id.longValue() % 3}"/> <rdb:data-source id="shardingDataSource"> <rdb:sharding-rule data-sources="dataSource"> <rdb:table-rules> <rdb:table-rule logic-table="t_order" actual-tables="t_order_${0..2}" table-strategy="tableShardingStrategy" /> </rdb:table-rules> </rdb:sharding-rule> </rdb:data-source>
单测
直接对MyBatis Mapper进行测试。
Order order = new Order(); order.setOrderId(1111); order.setUserId(222); Boolean result = orderMapper.insert(order) > 0; System.out.println(result?"插入成功":"插入失败");
OrderExample example = new OrderExample() ; example.createCriteria().andUserIdEqualTo(1112); List<Order> orderList = orderMapper.selectByExample(example) ; System.out.println(JSONObject.toJSONString(orderList));
使用SingleKeyTableShardingAlgorithm 实现分表规则
目标:每个业务线一个数据表(business_id:业务线Id)。
自定义的分表规则类需要实现SingleKeyTableShardingAlgorithm,并重写doBetweenSharding、doEqualSharding、doInSharding。
修改数据表
ALTER TABLE `t_order_0` ADD business_id INT(4) ; ALTER TABLE `t_order_1` ADD business_id INT(4) ; ALTER TABLE `t_order_2` ADD business_id INT(4) ; ALTER TABLE `t_order_0` RENAME t_order_112; ALTER TABLE `t_order_1` RENAME t_order_101; ALTER TABLE `t_order_2` RENAME t_order_113;
重新生成Mybatis Mapper相关文件
Spring 配置
<rdb:strategy id="tableShardingStrategy" sharding-columns="business_id" algorithm-class="com.boothsun.util.sharding.OrderSingleKeyTableShardingAlgorithm"/> <rdb:data-source id="shardingDataSource"> <rdb:sharding-rule data-sources="dataSource"> <rdb:table-rules> <rdb:table-rule logic-table="t_order" actual-tables="t_order_${[112,101,113]}" table-strategy="tableShardingStrategy" /> </rdb:table-rules> </rdb:sharding-rule> </rdb:data-source>
注意:这里使用的是algorithm-class而非algorithm-expression
OrderSingleKeyTableShardingAlgorithm 具体实现
/** * 每个业务线一个表 */ public class OrderSingleKeyTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Integer> { /** * 对于分片字段的between操作都走这个方法。 */ public Collection<String> doBetweenSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) { Collection<String> result = new LinkedHashSet<>(tableNames.size()); Range<Integer> range = shardingValue.getValueRange(); for (long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) { for (String each : tableNames) { if (each.endsWith(String.valueOf(i))) { result.add(each); } } } return result; } /** * 对于分片字段的等值操作 都走这个方法。(包括 插入 更新) */ public String doEqualSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) { String sdValue = String.valueOf(shardingValue.getValue()); for (String tableName : tableNames ) { if(tableName.endsWith(sdValue)) { return tableName ; } } throw new IllegalArgumentException("无分表参数 无法定位具体数据表"); } /** * 对于分片字段的in操作,都走这个方法。 */ public Collection<String> doInSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) { Collection<String> result = new LinkedHashSet<>(tableNames.size()); for (Integer value : shardingValue.getValues()) { for (String tableName : tableNames) { if (tableName.endsWith(String.valueOf(value))) { result.add(tableName); } } } return result; } }
单测类
/** * 测试插入 * @throws Exception */ @Test public void insertSelective() throws Exception { Order order = new Order(); order.setOrderId(123113); order.setUserId(222); order.setBusinessId(112); Boolean result = orderMapper.insert(order) > 0; System.out.println(result?"插入成功":"插入失败"); } /** * 测试 in 的查询操作 * @throws Exception */ @Test public void selectByExample2() throws Exception { List<Integer> values = new ArrayList<>(); values.add(112); values.add(113); OrderExample example = new OrderExample() ; example.createCriteria().andUserIdEqualTo(11333).andBusinessIdIn(values); List<Order> orderList = orderMapper.selectByExample(example) ; System.out.println(JSONObject.toJSONString(orderList)); } /** * 测试between的查询操作 * @throws Exception */ @Test public void selectByExample3() throws Exception { OrderExample example = new OrderExample() ; example.createCriteria().andBusinessIdBetween(112,113); List<Order> orderList = orderMapper.selectByExample(example) ; System.out.println(JSONObject.toJSONString(orderList)); }
来源:https://www.cnblogs.com/boothsun/p/7825853.html