shading-jdbc+mybatis 按月度字段分表

Sahrding-jdbc分表中间件整合说明

 

Sharding-JDBC是当当应用框架ddframe中,从关系型数据库模块dd-rdb中分离出来的数据库水平分片框架,实现透明化数据库分库分表访问。
Sharding-JDBC直接封装JDBC协议,可以理解为增强版的JDBC驱动,旧代码迁移成本几乎为零。 Sharding-JDBC定位为轻量级java框架,使用客户端直连数据库,jar包形式提供服务,无proxy代理层,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式。

 

1demo1mybatis+sharding-jdbc+spring boot

此案例为sharding-jdbc整合mybatis 的简单实现,其中sharding-jdbc的数据源配置及分表方式通过编写java代码并以注解的形式进行注册。

1.1分表规则

单库分表,在数据库中新建t_order_1t_order_2t_order_3t_order_4四张表,根据表中时间字段creat_time按照月份分表。

1.2 maven项目结构

 

 

1.3 引入maven依赖包pom.xml

其中sharding-jdbc的依赖包使用1.x版本

1.4 相关Java文件

1.4.1 普通类文件

 

以上Java文件均为正常java类,和普通项目相同,无需特殊处理;

1.4.2分表策略配置类

编写分表策略的java

配置sharding-jdbc数据源的类

1.4.3配置文件

application.properties:中配置数据库连接信息

 

 

1.5项目文件

详情见:springboot-mybatis-demo01

2、demo2jpa+sharding-jdbc+spring boot

此案例为jpa整合sharding-jdbc的简单实现,依旧为单库分表,所用到的数据库表以及分表规则与demo1中的相同;不同的是这个项目中主要通过增加配置文件的形式来完成分表策略的实现,需要增加的java类仅为分表规则的自定义实现类。具体方法详见如下步骤。

2.1 maven项目结构

 

2.2引入maven依赖包pom.xm

demo1java代码实现的方式不同,在使用配置文件实现分表时,除了sharding-jdbc-care核心jar,还需要sharding-jdbc-config-sprinng jar

 

详情见 文件

2.3相关java文件

2.3.1普通类文件

无需特殊改动,与普通不分表的项目相同

2.3.2分表策略实现类

需要在下面的配置文件中引入

2.3.3配置文件

在项目中引入配置文件,详细内容:

 

 

2.4项目文件

详情见:sharding-jdbc-jpa

3、demo3mybatis+sharding-jdbc  t_info表项目实践

此案例是针对项目中实际存在的一张大表做的拆分,在实际项目中关于此表的sql中涉及到分页、left join关联、时间字段格式化函数、查询条件中包含子查询等复杂的sql,下面会针对具体的sql进行改写,以达到直接查询目标表并返回正确结果的目的。

3.1分表规则

针对t_info这张表,根据时间字段input_time取其月份值,在数据库中创建t_info_01t_info_02t_info_03t_info_04表;与其关联的main_user表不做拆分。

3.2 maven项目结构

 

3.3 配置文件

 

 

3.4 分表规则类ModloTableShardingAlgorithm

ModloTableShardingAlgorithm.java是实现了有sharding-jdbcjar包中提供的SingleKeyTableShardingAlgorithm接口,实现三个方法,根据实际需要自定义编写分表规则

 

3.5 SQL解析

针对项目中所用到的t_info表,分表后sql需改造的情况如下:

1. 使用sharding-jdb后不支持distinct操作

2. 原本的查询SQL中,用到了left join,会导致扫描所有表

3. 涉及分页查询,针对子查询结果在再分页会导致扫描所有表

4. 因为t_info表是按照时间字段input_time进行拆分的,所以为了达到直接扫描目标表的效果,需要在查询条件中传入input_time的条件值,以达到提高查询速度的效果

5. 针对分片字段input_time 在使用日期格式化函数时也会导致扫描所有表,所以建议在代码中格式化后再传入。

 

3.6项目文件

详情见:sharding-jdbc-mybatis-demo02

4、Sharding-jdbcSQL支持情况总结

在使用分表设计的项目中,想达到直接扫描目标表的效果前提条件是where条件中必须传入分表字段。

下面提到的表t_order为逻辑表,实际的物理表为t_order_1...t_order_4,分片字段为creat_time,分片规则为取其月份分表)

4.1 SQL关键字使用

4.1.1 扫描所有分表

1. SQL中针对分表字段使用LIKEto_days()函数、<=,扫描所有表

例:SELECT*FROM t_order WHERE creat_time like #{creat_time}

SELECT*FROM t_order WHERE to_days(creat_time)= to_days(#{creat_time})

SELECT*FROM t_order WHERE creat_time <= #{creat_time}

4.1.2 扫描目标表

1. 针对分片字段使用between and 并直接传值,可以扫描对应的表

例:SELECT*FROM t_order WHERE creat_time BETWEEN #{creat_time} AND #{creat_time1}

2.关于针对单表使用COUNTMAXMIN,并对分表字段传入条件值,可以直接扫描目标表

例:select count(*) from t_order where 1=1 and creat_time BETWEEN ? and ?

select max(id) from t_order where 1=1 and creat_time BETWEEN ? and ?

select min(id) from t_order where 1=1 and creat_time BETWEEN ? and ?

3.sql中使用group by 分组函数时,并对分表字段出入条件值,可以直接扫描目标表

例:select * from t_order where creat_time =? group by id

4.1.3 不支持使用的sql关键字

1. SQL语句中针对所有字段使用OR DISTINCTUNIONhaving,会报错

例:select distinct t_order.id,t_order.name .....from t_order.....

 

 

 

2. SQL语句中针对分表字段使用between()and时,其中的参数包含子查询,会报错

例:SELECT*FROM t_order WHERE creat_time BETWEEN(select creat_time from t_order_1 where user_id=6) AND #{creat_time}

4.2 SQL中包含子查询

4.2.1 扫描所有分表

1.  SQL语句的where 条件没有传入分表的字段值,扫描所有表

例:SELECT * FROM  t_order

2.  SQL语句中包含冗余括号的子查询,扫描所有表

例:select*from(<include refid="selectSql"/>) x limit 0,100

注:selectSql为“SELECT * FROM  t_order where creat_time=”20180430””

4.2.2 扫描目标表

1.在查询条件中针对非分表字段含有子查询、分表字段传入条件值,可以直接扫描目标表

例:SELECT*FROM t_order WHERE 1=1 AND userName in (select userName from    t_order_1 where user_id="6")AND creat_time BETWEEN '20180419' and '20180420'

 

4.3 SQL联表查询

4.3.1 扫描所有分表

1.SQL中使用left join进行联表查询,并传入了分表字段,扫描所有表

例:from t_order LEFT JOIN main_users on t_order.u_ch_id = main_users.uid where 1=1
    and creat_time BETWEEN#{creatTime,jdbcType=TIMESTAMP}and #{creatTime1,jdbcType=TIMESTAMP}

4.3.2 扫描目标表

1.拆分的表与未进行拆分的表进行联表查,并传入分表字段值,可以直接扫描目标表

例:From t_ordermain_users where t_order.u_ch_id=main_users.uid

and t_order.creat_time BETWEEN  #{creatTime,jdbcType=TIMESTAMP}and #{creatTime1,jdbcType=TIMESTAMP}

 

4.4 关于DML语句的支持

4.4.1 INSERT

1.insert语句针对分表字段使用SYSDATE()获取数据库系统时间,会报错

例:INSERT INTO t_order
(order_id,user_id,userName,passWord,user_sex,description,creat_time)
VALUES
(#{order_id},#{user_id},#{userName},#{passWord},#{userSex},#{description},SYSDATE())

 

2. insert语句中,针对分表字段必须传入正确的值,才可以直接插入到目标表

例:insert into t_order (id,name,creat_time) values (  “2”,”啊啊啊”,”2018-04-27”);

4.4.2 UPDATE

1.update语句中,如果where条件中没有分表字段,则会修改所有分表中满足条件的数据

例:update t_order set name=? where id=?

 

2.update语句中,如果where条件含有分表字段,则只修改目标表的数据

例:update t_order set name=? where id=? and creat_time=?

 

4.4.3 DELETE

1.delete语句中,如果where条件中没有分表字段,则会删除所有分表中满足条件的数据

例:delete from t_order where id = ?

2.delete语句中,如果where条件含有分表字段,则只修改目标表的数据

例:delete from t_order where id=? and creat_time=?

 

针对上述DML语句案例分析,各个分表间的主键id不应有重复(例如不能使用int自增型)。

4.5 关于事务的支持

 

针对数据库事务得的操作,只需自爱配置事务的数据源时引用shardingDataSource

 

在需要事务的地方使用@Transactional注解

 

注:

在使用Transactional注解时,数据库引擎要支持事务,如果是MySQL,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的

阅读更多 登录后自动展开
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页