在《“分库分表" ?选型和流程要慎重,否则会失控》中,我们谈到处于驱动层的sharding-jdbc。开源做到这个水平,已经超棒了,不像tddl成了个太监。但还是有坑。

不过不能怪框架,毕竟有些sql,只有程序和鬼能懂。

<select id="getCodes" resultMap="BaseResultMap" parameterType="java.util.Map"><foreach collection="orderCodes" index="index" item="item" open="" separator="union all"close="">select<include refid="Base_Column_List"/>from orderwhere  orderCode =  #{item}</foreach>
</select>
复制代码

不支持的操作

分库分表后,就成为了一个阉割型的数据库。很多sql的特性是不支持的,需要使用其他手段改进。以下以3.0.0版本进行描述。

distinct

sharding-jdbc不支持distinct,单表可使用group by进行替代。多表联查可使用exists替代

select DISTINCTa, b, c, dfrom  tablewhere df=0
复制代码

改成

select a, b, c, dfrom  tablewhere df=0group by a, b, c, d
复制代码

having

sharding-jdbc不支持having,可使用嵌套子查询进行替代

union

sharding-jdbc不支持union(all),可拆分成多个查询,在程序拼接

关于子查询

sharding-jdbc不支持在子查询中出现同样的表,如 以下可以==>

SELECT COUNT(*) FROM (SELECT * FROM t_order o)
复制代码

以下报错==>

SELECT COUNT(*) FROM (SELECT * FROM t_order o WHERE o.id IN (SELECT id FROM t_order WHERE status = ?))
复制代码

由于归并的限制,子查询中包含聚合函数目前无法支持。

mybatis 注释

sharding-jdbc不支持sql中的<!-- – >注释,如必须使用则写在sql前,或使用/* */

不支持text字段

改为varchar,好几年的bug了,但是没改

case when

某些case when是不支持的,比如不在聚合函数中的case when,需要将这部分sql逻辑写到程序里。

case when不应该是DBA禁用的函数么?我们在填坑

一些奇怪的反应

这个是可以的

select  a-b from dual
复制代码

但这个不可以...

select (a-b)c from dual
复制代码

sharding 也不支持如下形式查询,解析紊乱

and (1=1 or 1=1)
复制代码

关于分页

严禁无切分键的深分页!因为会对SQL进行以下解释,然后在内存运行。

select *  from a limit 10 offset 1000
复制代码

=======>

Actual SQL:db0 ::: select *  from a limit 1010 offset 0
复制代码

关于表名

表名需与sharding-jdbc配置一致,推荐均为小写。因为路由是放在hashmap里的,没有区分大小写...所以如果你的sql写错了会找不到。

配置冗余

每一张表都要配置路由信息才能够被正确解析,如果你库里的表太多,这个配置文件会膨胀的特别大,上千行也是有的。所以在yml中可以将配置文件分开。

spring.profiles.include: sharding
复制代码

如何扫多库

比如一些定时任务,需要遍历所有库。

方法1:遍历所有库

使用以下方式拿到真正的数据库列表

Map<String, DataSource> map = ShardingDataSource.class.cast(dataSource).getDataSourceMap();
复制代码

然后在每一个库上执行扫描逻辑。这种情况下无法使用mybaits,需要写原生jdbc

方法2:根据切分键遍历

此种方法会拿到一个切分键的列表,比如日期等。然后通过遍历这个列表执行业务逻辑。此种方法在列表特别大的时候执行会比较缓慢。

如何验证

分库分表很危险,因为一旦数据入错库,后续的修理很麻烦。所以刚开始可以将路由信息指向到源表,即:只验证SQL路由的准确性。等待所有的SQL路由都验证通过,再切换到真正的分库或者表。

确保能够打印SQL

sharding.jdbc.config.sharding.props.sql.show: true
复制代码

将sql打印到单独的文件(logback)

<appender name="SQL" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_HOME}/sharding.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_HOME}/backup/sharding.log.%d{yyyy-MM-dd}</fileNamePattern><maxHistory>100</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
复制代码

写一些脚本进行SQL文件的验证。我这里有个通用的,你可以改下你的逻辑。

import sys
import re
import getoptdef process(SQL):one= "".join(line.strip().replace("\n", " ") for line in SQL)place = [m.groups()[0] if m.groups()[0] else m.groups()[1] for m in re.finditer(r"[ ]+(\w+)[ ]*=[ ]*\?|(\?)", one)]if len(place):mat = re.search(r"::: \[\[(.*)\]\]", one)if mat is not None:vals = [str(i).strip() for i in str(mat.groups()[0]).split(',')]if "splitKey" in place:for i in range(len(place)):part = place[i]//这里写你的逻辑else:print("no splitKey", one)SQL = []
def process_line(line):global SQLif "Actual SQL" in line:SQL = []SQL.append(line)else:if line.strip().endswith("]]"):SQL.append(line)process(SQL)SQL = []else:SQL.append(line)opts, args = getopt.getopt(sys.argv[1:], "bf")for op, value in opts:if op == "-b":print("enter comman mode , such as 'python x.py -b sharding.log > result'")with open(args[0], "rb") as f:for line in f:process_line(line)elif op== "-f":print("enter stream scroll mode , such as 'python x.py -f sharding.log '")with open(args[0], "rb") as f:f.seek(0,2)while True:last_pos = f.tell()line = f.readline()if line: process_line(line)
复制代码

其他

你可能要经常切换路由,所以某些时候路由信息要放在云端能够动态修改。

哦对了,我这里还有一段开发阶段的验证代码,能让你快速验证SQL能否正确解析。


@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)public class ShardingTest {@AutowiredDataSource dataSource;@Testpublic void testGet() {try {Connection conn = dataSource.getConnection();PreparedStatement stmt;ResultSet rs;String sql = new String(Files.readAllBytes(Paths.get("/tmp/a.sql")));stmt = conn.prepareStatement(sql);rs = stmt.executeQuery();printRS(rs);} catch (Exception ex) {ex.printStackTrace();}}public static void printRS(ResultSet rs) throws Exception {ResultSetMetaData rsmd = rs.getMetaData();int columnsNumber = rsmd.getColumnCount();while (rs.next()) {for (int i = 1; i <= columnsNumber; i++) {if (i > 1) System.out.print(",  ");String columnValue = rs.getString(i);System.out.print(columnValue + " " + rsmd.getColumnName(i));}System.out.println("");}}
}
复制代码

有SQL规范的团队是幸福的,分库分表简单的很。而动辄几百行,有各种复杂函数的SQL,就只能一步一个坑了。

话说回来,如果不是为了事务这个特性,为了支持老掉牙的业务,谁会用这分完后人不像人,鬼不像鬼的东西。

非规范SQL的sharding-jdbc实践相关推荐

  1. Spring boot + Sharding JDBC 分库分表 及 分布式事务处理

    Sharding JDBC 基础概念 Apache ShardingSphere 是一套开源的分布式数据库解决方案组成的生态圈,它由 JDBC.Proxy 和 Sidecar(规划中)这 3 款既能够 ...

  2. SpringBoot + Sharding JDBC,一文搞定分库分表、读写分离

    程序员的成长之路 互联网/程序员/技术/资料共享 关注 阅读本文大概需要 30 分钟. 来自:blog.csdn.net/qq_40378034/article/details/115264837 S ...

  3. SpringBoot + Sharding JDBC 读写分离、分库分表

    Sharding-JDBC 最早是当当网内部使用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名为 ShardingSphere,20 ...

  4. 【MySQL 读写分离】Sharding JDBC + Spring boot 实现数据库读写分离的登录 Demo

    上篇文章我们搭建了 MySQL 数据库主从复制集群 MySQL 搭建主从复制集群~~~ 本篇文章我们利用搭建好的主从复制集群,使用 SpringBoot 结合 Sharding-JDBC 搭建一个小的 ...

  5. Sharding JDBC分片和读写分离详解

    目录 Sharding Sphere简介 开始使用Sharding JDBC 数据分片 简单示例 Spring Boot示例 代码分析 属性分析 绑定表和广播表 真实表 绑定表 广播表 Shardin ...

  6. Spring boot项目集成Sharding Jdbc

    环境 jdk:1.8 framework: spring boot, sharding jdbc database: MySQL 搭建步骤 在pom 中加入sharding 依赖 <depend ...

  7. Sharding JDBC(四) 分片策略一:标准分片策略StandardShardingStrategy

    目录 一.标准分片策略StandardShardingStrategy 二.StandardShardingStrategy配置实现 分库分表最核心的两点SQL 路由  . SQL 改写 applic ...

  8. 理解Sharding jdbc原理,看这一篇就够了

    相比于Spring基于AbstractRoutingDataSource实现的分库分表功能,Sharding jdbc在单库单表扩展到多库多表时,兼容性方面表现的更好一点.例如,spring实现的分库 ...

  9. SSM项目引入sharding JDBC进行分表

    SSM项目引入sharding JDBC进行分表 注意点: 本次集成sharing-jdbc 4.1.1,由于各个版本差别比较大,配置方式差别也特别大,请根据官方文档进行配置! 官方配置路径:http ...

最新文章

  1. java 执行 cmd 命令(转)
  2. 数据中台全景架构及模块解析
  3. PHP 入门 - 4.正则表达式
  4. 关于RMQ问题的四种解法
  5. java的二叉树及三种遍历
  6. 苹果手机的隔空投送怎么使用?
  7. 社交系统ThinkSNS+版本的 SPA(H5)安装教程
  8. Vue登录注册,并保持登录状态 1
  9. pycharm—误删代码怎么办
  10. gridreport php教程,谁能教我怎样才能把Grid++Report插件插入到.w页面中?
  11. arcgis交通可达性分析步骤_可达性分析(二):基于Network Analys的服务区分析
  12. sas导出数据串行解决方案
  13. Vue的MVVM框架
  14. python毕业论文参考文献格式范例_毕业论文参考文献规范格式及范例
  15. 01_CCC3.0数字钥匙_蓝牙OOB配对过程
  16. JDK13 Switch表达式新特性
  17. 微信公众号开发 糟糕的体验_糟糕的开发人员–好老板
  18. VS Code利用GIT对源码进行管理
  19. 在win10中安装caffe并配置MATLAB和Python接口(支持GPU加速)
  20. 专访STEM领域人才资深人工智能图像算法工程师张旦

热门文章

  1. 这可能是由于 CredSSP 加密 Oracle 修正。
  2. word中中文保持正体,英文用斜体的方法.
  3. Python学习笔记__4.1章 高阶函数
  4. 数据即代码:元驱动编程
  5. VC中显示ICON和BMP图片
  6. 一个复杂系统的拆分改造实践
  7. HTTP错误404.3-Not Found
  8. 【遇到问题】ORA-27102 ORA-01034
  9. nstruts2.0发布前奏---浅谈struts和依赖注入在项目中的应用
  10. 不要再说找不到前端项目练手了!