一. Sharding JDBC介绍
Sharding-Sphere的前身Sharding-JDBC是由当当的应用框架dd-frame中的dd-rdb模块演进而来, 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar这3款相互独立的产品组成。
Sharding-JDBC 可适用于任何基于Java的ORM框架,如JPA、Hibernate、MyBatis、Spring JDBC Template等, 支持第三方的数据库连接池,如DBCP、C3P0、BoneCP、Druid等。
二. Sharding JDBC的使用限制
Sharding JDBC, Mycat, Drds 等产品都是分布式数据库中间件, 相比直接的数据源操作, 会存在一些限制, Sharding JDBC在使用时, 要注意以下问题:
- 有限支持子查询
- 不支持HAVING
- 不支持OR,UNION 和 UNION ALL
- 不支持特殊INSERT
- 每条INSERT语句只能插入一条数据,不支持VALUES后有多行数据的语句
- 不支持DISTINCT聚合
- 不支持dual虚拟表查询
- 不支持SELECT LAST_INSERT_ID(), 不支持自增序列
- 不支持CASE WHEN
三. Sharding JDBC的集成配置
-
POM依赖
<!-- sharding-jdbc 依赖 --> <dependency> <groupId>io.shardingsphere</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>3.1.0</version> </dependency>
-
实现分库分片配置:
假设数据库表结构:
订单表(t_order)字段: 订单ID(orderId), 年份(year)
分库规则为: 根据年份分库, 比如2019, 对应的数据库为DB_2019; 年份2020, 对应的库为DB_2020.
分表规则为: 根据订单ID取模, 散落分配在3个表中.
具体实现:-
定义分库规则
public class DBSplitRule implements PreciseShardingAlgorithm<String> { /** * 分库规则设置 * @param collection * @param preciseShardingValue * @return */ @Override public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) { // 取出属性值 String year = preciseShardingValue.getValue(); // 根据属性值判断处理 if("2019".equals(year)) { return "DB_2019"; }else if("2020".equals(year)){ return "DB_2020"; } return "DB_2020"; } }
-
定义分片规则
@Log4j2 public class TableSplitRule implements PreciseShardingAlgorithm<Integer> { /** * 制定分片规则 */ @Override public String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) { log.info("Process in TableSplitRule .doSharding method, collection: " + collection + ", collection: " + preciseShardingValue); String tableName = preciseShardingValue.getLogicTableName() + "_"; try { // 获取类型值 Long orderId = preciseShardingValue.getValue(); long mod = Math.floorMod(orderId, 3l); if(mod == 1) { // 第一个表 tableName = tableName + "_1"; }else if(mod == 2) { // 第二个表 tableName = tableName + "_2"; }else if(mod == 3) { // 第三个表 tableName = tableName + "_3"; }else { throw new Exception("Not Match Table, result: " + mod); } log.info("result table name:" + tableName); return tableName; } catch (Exception e) { log.error(e.getMessage(), e); throw new RuntimeException(e.getMessage()); } } }
-
Sharding Jdbc 数据源配置
这里是基于Druid连接池实现的集成配置.@Configuration public class DruidDataSourceConfiguration { /** * 分表配置规则 */ private TableRuleConfiguration getSplitOrderTableRule() { TableRuleConfiguration result = new TableRuleConfiguration(); // 指定需要通过sharding-jdbc路由的表 result.setLogicTable("t_order"); // 分库配置, 代表数据库根据年份分了两个库, 表t_order分了1至3共3个表 result.setActualDataNodes("DB_${2019..2020}.t_order_${1..3}"); // 分库规则配置 result.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("year", new DBSplitRule ())); result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("orderId", new TableSplitRule ())); return result; } /** * 数据源配置 * @return */ @Bean(name = "shardingDataSource") public DataSource shardingDataSource(@Autowired DruidDataSource druidDataSource) throws Exception{ ShardingRuleConfiguration shardJdbcConfig = new ShardingRuleConfiguration(); shardJdbcConfig.getTableRuleConfigs().add(getSplitOrderTableRule()); shardJdbcConfig.setDefaultDataSourceName("DB_2020"); Map<String,DataSource> dataMap = new LinkedHashMap<>() ; // 多个分库配置对应的数据源配置 dataMap.put("DB_2019",druidDataSource) ; dataMap.put("DB_2020",druidDataSource) ; Properties prop = new Properties(); prop.put("sql.show", true); return ShardingDataSourceFactory.createDataSource(dataMap, shardJdbcConfig, new HashMap<>(), prop); } }
这里实现了订单的分表, 通过getSplitOrderTableRule方法配置了订单表的分表规则, 如果还需要对其他表做分表处理, 可以参照getSplitOrderTableRule新增方法追加规则配置.
-
-
全局序列ID配置及注意的问题
前面讲过, Sharding JDBC 不支持自增序列,
如果通过JPA对数据层进行操作, 需要去除@GeneratedValue(strategy = GenerationType.IDENTITY)
如果数据库是Postgresql, 数据库属性是采用小写, 我们要加上映射@Column(name=“orderid”), 否则SQL处理的时候会报错:java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(ArrayList.java:657) at java.util.ArrayList.get(ArrayList.java:433) at io.shardingsphere.core.executor.sql.execute.result.MemoryQueryResult.getColumnIndex(MemoryQueryResult.java:151)
本文由mirson创作分享,如需进一步交流,请加QQ群:19310171或访问www.softart.cn