Sharding-JDBC笔记03-分库分表代码示例
文章目录
- 一、水平分库
- 1. 将原有order_db库拆分为order_db_1、order_db_2
- 2. 分片规则修改
- 分片策略
- standard
- complex
- inline
- hint
- none
- 3. 插入测试
- 4. 查询测试
- 5. 使用分库分片键查询测试
- 总结
- 二、公共表
- 1. 创建数据库
- 2. 在Sharding-JDBC规则中修改
- 3. 数据操作
- 4. 字典操作测试
- 5. 字典关联查询测试
- 总结分库分表配置大概流程:
- 三、读写分离
- 1.理解读写分离
- 2.实现sharding-jdbc读写分离
- 1. 在Sharding-JDBC规则中修改
一、水平分库
前面已经介绍过,水平分表是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中。并且在前面的文章中(快速入门),我们已经对水平分库进行代码实现,这里不再重复介绍。
水平分库是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。接下来看一下如何使用Sharding-JDBC实现水平分库,咱们继续对快速入门中的例子进行完善。
1. 将原有order_db库拆分为order_db_1、order_db_2

数据库表
CREATE DATABASE `order_db_1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
CREATE DATABASE `order_db_2` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`price` decimal(10, 2) NOT NULL COMMENT '订单价格',
`user_id` bigint(20) NOT NULL COMMENT '下单用户id',
`status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
DROP TABLE IF EXISTS `t_order_2`;
CREATE TABLE `t_order_2` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`price` decimal(10, 2) NOT NULL COMMENT '订单价格',
`user_id` bigint(20) NOT NULL COMMENT '下单用户id',
`status` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '订单状态',
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
引入maven依赖
<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding‐jdbc‐spring‐boot‐starter</artifactId><version>4.0.0‐RC1</version>
</dependency>
2. 分片规则修改
由于数据库拆分了两个,这里需要配置两个数据源。
分库需要配置分库的策略,和分表策略的意义类似,通过分库策略实现数据操作针对分库的数据库进行操作。
# 定义多个数据源
server.port=8889spring.application.name = sharding-jdbc-simple-demoserver.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = truespring.main.allow-bean-definition-overriding = truemybatis.configuration.map-underscore-to-camel-case = true#sharding-jdbc分片规则配置
#数据源
spring.shardingsphere.datasource.names = m1,m2spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url = jdbc:mysql://localhost:3308/order_db_1?useUnicode=true
spring.shardingsphere.datasource.m1.username = root
spring.shardingsphere.datasource.m1.password = 123456spring.shardingsphere.datasource.m2.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m2.url = jdbc:mysql://localhost:3308/order_db_2?useUnicode=true
spring.shardingsphere.datasource.m2.username = root
spring.shardingsphere.datasource.m2.password = 123456# 分库策略,以user_id为分片键,分片策略为user_id % 2 + 1,user_id为偶数操作m1数据源,否则操作m2。
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column = user_id
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression = m$->{user_id % 2 + 1}# 指定t_order表的数据分布情况,配置数据节点 m.t_order_1,m1.t_order_2,m2.t_order_1,m2.t_order_21
# 如果这里配置如m1.t_order_$->{1..2},则查询时只会查询m1库的表
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m$->{1..2}.t_order_$->{1..2}# 指定t_order表的主键生成策略为SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE# 指定t_order表的分片策略,分片策略包括分片键和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 2 + 1}# 打开sql输出日志
spring.shardingsphere.props.sql.show = trueswagger.enable = truelogging.level.root = info
logging.level.org.springframework.web = info
logging.level.com.itheima.dbsharding = debug
logging.level.druid.sql = debug
分库策略定义方式如下:
#分库策略,如何将一个逻辑表映射到多个数据源
spring.shardingsphere.sharding.tables.<逻辑表名称>.database‐strategy.<分片策略>.<分片策略属性名> = #分片策略属性值
#分表策略,如何将一个逻辑表映射为多个实际表
spring.shardingsphere.sharding.tables.<逻辑表名称>.table‐strategy.<分片策略>.<分片策略属性名> = #分片策略属性值
分片策略
Sharding-JDBC支持以下几种分片策略:
不管理分库还是分表,策略基本一样。
standard
standard:标准分片策略,对应StandardShardingStrategy。
提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。
StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。
PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。
RangeShardingAlgorithm是可选的,用于处理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。
complex
complex:符合分片策略,对应ComplexShardingStrategy。复合分片策略。
提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。
ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。
inline
inline:行表达式分片策略,对应InlineShardingStrategy。
使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。
对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为 t_user_0 到t_user_7 。
hint
hint:Hint分片策略,对应HintShardingStrategy。
通过Hint而非SQL解析的方式分片的策略。对于分片字段非SQL决定,而由其他外置条件决定的场景,可使用SQL Hint灵活的注入分片字段。
例:内部系统,按照员工登录主键分库,而数据库中并无此字段。SQL Hint支持通过Java API和SQL注释(待实现)两种方式使用。
none
none:不分片策略,对应NoneShardingStrategy。不分片的策略。
目前例子中都使用inline分片策略,若对其他分片策略细节若感兴趣,请查阅官方文档:
https://shardingsphere.apache.org
3. 插入测试
修改testInsertOrder方法,插入数据中包含不同的user_id
@Test
public void testInsertOrder(){for(int i=1;i<20;i++){//插入时根据分库策略,userId为奇数时插入到sharding_db_2中(偶数则sharding_db_1)orderDao.insertOrder(new BigDecimal(i),2L,"SUCCESS");}
}
执行testInsertOrder输出:
...
2024-09-02 21:21:50.473 INFO 25308 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-02 21:21:50.473 INFO 25308 --- [ main] ShardingSphere-SQL : Logic SQL: insert into t_order(price,user_id,status)values(?,?,?)
2024-09-02 21:21:50.473 INFO 25308 --- [ main] ShardingSphere-SQL : SQLStatement: InsertStatement(super=DMLStatement(super=AbstractSQLStatement(type=DML, tables=Tables(tables=[Table(name=t_order, alias=Optional.absent())]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[Condition(column=Column(name=user_id, tableName=t_order), operator=EQUAL, compareOperator=null, positionValueMap={}, positionIndexMap={0=1})])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_order, quoteCharacter=NONE, schemaNameLength=0), SQLToken(startIndex=19)], parametersIndex=3, logicSQL=insert into t_order(price,user_id,status)values(?,?,?)), deleteStatement=false, updateTableAlias={}, updateColumnValues={}, whereStartIndex=0, whereStopIndex=0, whereParameterStartIndex=0, whereParameterEndIndex=0), columnNames=[price, user_id, status], values=[InsertValue(columnValues=[org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@518ddd3b, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@939ff41, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@6e0e5dec])])
2024-09-02 21:21:50.474 INFO 25308 --- [ main] ShardingSphere-SQL : Actual SQL: m2 ::: insert into t_order_1 (price, user_id, status, order_id) VALUES (?, ?, ?, ?) ::: [18, 1, SUCCESS, 1037476657251745792]
2024-09-02 21:21:50.476 DEBUG 25308 --- [ main] c.i.d.simple.dao.OrderDao.insertOrder : <== Updates: 1
2024-09-02 21:21:50.476 DEBUG 25308 --- [ main] c.i.d.simple.dao.OrderDao.insertOrder : ==> Preparing: insert into t_order(price,user_id,status)values(?,?,?)
2024-09-02 21:21:50.476 DEBUG 25308 --- [ main] c.i.d.simple.dao.OrderDao.insertOrder : ==> Parameters: 19(BigDecimal), 1(Long), SUCCESS(String)
2024-09-02 21:21:50.476 INFO 25308 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-02 21:21:50.476 INFO 25308 --- [ main] ShardingSphere-SQL : Logic SQL: insert into t_order(price,user_id,status)values(?,?,?)
2024-09-02 21:21:50.476 INFO 25308 --- [ main] ShardingSphere-SQL : SQLStatement: InsertStatement(super=DMLStatement(super=AbstractSQLStatement(type=DML, tables=Tables(tables=[Table(name=t_order, alias=Optional.absent())]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[Condition(column=Column(name=user_id, tableName=t_order), operator=EQUAL, compareOperator=null, positionValueMap={}, positionIndexMap={0=1})])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_order, quoteCharacter=NONE, schemaNameLength=0), SQLToken(startIndex=19)], parametersIndex=3, logicSQL=insert into t_order(price,user_id,status)values(?,?,?)), deleteStatement=false, updateTableAlias={}, updateColumnValues={}, whereStartIndex=0, whereStopIndex=0, whereParameterStartIndex=0, whereParameterEndIndex=0), columnNames=[price, user_id, status], values=[InsertValue(columnValues=[org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@518ddd3b, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@939ff41, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@6e0e5dec])])
2024-09-02 21:21:50.476 INFO 25308 --- [ main] ShardingSphere-SQL : Actual SQL: m2 ::: insert into t_order_2 (price, user_id, status, order_id) VALUES (?, ?, ?, ?) ::: [19, 1, SUCCESS, 1037476657264328705]
2024-09-02 21:21:50.478 DEBUG 25308 --- [ main] c.i.d.simple.dao.OrderDao.insertOrder : <== Updates: 1
通过日志可以看出,根据user_id的奇偶不同,数据分别落在了不同数据源,达到目标。
4. 查询测试
调用快速入门的查询接口进行测试:
@Test
public void testSelectOrderbyIds(){List<Long> ids = new ArrayList<>();ids.add(1037479531180457984L);ids.add(1037479530777804801L);List<Map> maps = orderDao.selectOrderbyIds(ids);System.out.println(maps);
}
通过日志发现,sharding-jdbc将sql路由到m1和m2:
2024-09-02 21:34:14.292 DEBUG 29104 --- [ main] c.i.d.s.dao.OrderDao.selectOrderbyIds : ==> Preparing: select * from t_order t where t.order_id in ( ? , ? )
2024-09-02 21:34:14.308 DEBUG 29104 --- [ main] c.i.d.s.dao.OrderDao.selectOrderbyIds : ==> Parameters: 1037479531180457984(Long), 1037479530777804801(Long)
2024-09-02 21:34:14.678 INFO 29104 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-02 21:34:14.679 INFO 29104 --- [ main] ShardingSphere-SQL : Logic SQL: select * from t_order t where t.order_id in ( ? , ? )
2024-09-02 21:34:14.679 INFO 29104 --- [ main] ShardingSphere-SQL : SQLStatement: SelectStatement(super=DQLStatement(super=AbstractSQLStatement(type=DQL, tables=Tables(tables=[Table(name=t_order, alias=Optional.of(t))]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[Condition(column=Column(name=order_id, tableName=t_order), operator=IN, compareOperator=null, positionValueMap={}, positionIndexMap={0=0, 1=1})])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_order, quoteCharacter=NONE, schemaNameLength=0)], parametersIndex=2, logicSQL=select * from t_order t where t.order_id in ( ? , ? ))), containStar=true, firstSelectItemStartIndex=7, selectListStopIndex=7, groupByLastIndex=0, items=[StarSelectItem(owner=Optional.absent())], groupByItems=[], orderByItems=[], limit=null, subqueryStatement=null, subqueryStatements=[], subqueryConditions=[])
2024-09-02 21:34:14.680 INFO 29104 --- [ main] ShardingSphere-SQL : Actual SQL: m1 ::: select * from t_order_1 t where t.order_id in ( ? , ? ) ::: [1037479531180457984, 1037479530777804801]
2024-09-02 21:34:14.680 INFO 29104 --- [ main] ShardingSphere-SQL : Actual SQL: m1 ::: select * from t_order_2 t where t.order_id in ( ? , ? ) ::: [1037479531180457984, 1037479530777804801]
2024-09-02 21:34:14.680 INFO 29104 --- [ main] ShardingSphere-SQL : Actual SQL: m2 ::: select * from t_order_1 t where t.order_id in ( ? , ? ) ::: [1037479531180457984, 1037479530777804801]
2024-09-02 21:34:14.680 INFO 29104 --- [ main] ShardingSphere-SQL : Actual SQL: m2 ::: select * from t_order_2 t where t.order_id in ( ? , ? ) ::: [1037479531180457984, 1037479530777804801]
2024-09-02 21:34:14.721 DEBUG 29104 --- [ main] c.i.d.s.dao.OrderDao.selectOrderbyIds : <== Total: 2
当只查询偶数结尾的id时
@Testpublic void testSelectOrderbyId(){//观察查询一个id和多个id的区别List<Long> ids = new ArrayList<>();ids.add(1037479531180457984L);
// ids.add(1037479530777804801L);List<Map> maps = orderDao.selectOrderbyIds(ids);System.out.println(maps);}
通过日志发现,sharding-jdbc将sql路由到m1和m2,并且只查询两个库中的t_order_1表:
2024-09-02 21:35:15.602 DEBUG 35388 --- [ main] c.i.d.s.dao.OrderDao.selectOrderbyIds : ==> Preparing: select * from t_order t where t.order_id in ( ? )
2024-09-02 21:35:15.616 DEBUG 35388 --- [ main] c.i.d.s.dao.OrderDao.selectOrderbyIds : ==> Parameters: 1037479531180457984(Long)
2024-09-02 21:35:15.989 INFO 35388 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-02 21:35:15.990 INFO 35388 --- [ main] ShardingSphere-SQL : Logic SQL: select * from t_order t where t.order_id in ( ? )
2024-09-02 21:35:15.991 INFO 35388 --- [ main] ShardingSphere-SQL : SQLStatement: SelectStatement(super=DQLStatement(super=AbstractSQLStatement(type=DQL, tables=Tables(tables=[Table(name=t_order, alias=Optional.of(t))]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[Condition(column=Column(name=order_id, tableName=t_order), operator=IN, compareOperator=null, positionValueMap={}, positionIndexMap={0=0})])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_order, quoteCharacter=NONE, schemaNameLength=0)], parametersIndex=1, logicSQL=select * from t_order t where t.order_id in ( ? ))), containStar=true, firstSelectItemStartIndex=7, selectListStopIndex=7, groupByLastIndex=0, items=[StarSelectItem(owner=Optional.absent())], groupByItems=[], orderByItems=[], limit=null, subqueryStatement=null, subqueryStatements=[], subqueryConditions=[])
2024-09-02 21:35:15.991 INFO 35388 --- [ main] ShardingSphere-SQL : Actual SQL: m1 ::: select * from t_order_1 t where t.order_id in ( ? ) ::: [1037479531180457984]
2024-09-02 21:35:15.991 INFO 35388 --- [ main] ShardingSphere-SQL : Actual SQL: m2 ::: select * from t_order_1 t where t.order_id in ( ? ) ::: [1037479531180457984]
2024-09-02 21:35:16.073 DEBUG 35388 --- [ main] c.i.d.s.dao.OrderDao.selectOrderbyIds : <== Total: 1
5. 使用分库分片键查询测试
由于查询语句中并没有使用分片键user_id,所以sharding-jdbc将广播路由到每个数据结点。
下边我们在sql中添加分片键进行查询。
在OrderDao中定义接口:
@Mapper
@Component
public interface OrderDao {/*** 根据id列表和用户id查询订单* @param orderIds* @return*/@Select("<script>" +"select" +" * " +" from t_order t " +" where t.order_id in " +" <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" +" #{id} " +" </foreach>" +" and user_id = #{userId} " +"</script>")List<Map> selectOrderbyUserAndIds(@Param("userId") Long userId,@Param("orderIds") List<Long> orderIds);
}
编写测试方法:
@Testpublic void testSelectOrderbyUserAndIds(){List<Long> ids = new ArrayList<>();ids.add(1037479531180457984L);
// ids.add(1037479530777804801L);List<Map> maps = orderDao.selectOrderbyUserAndIds(2L,ids);System.out.println(maps);}
查看输出日志:
2024-09-02 21:42:30.440 DEBUG 16652 --- [ main] c.i.d.s.d.O.selectOrderbyUserAndIds : ==> Preparing: select * from t_order t where t.order_id in ( ? ) and user_id = ?
2024-09-02 21:42:30.455 DEBUG 16652 --- [ main] c.i.d.s.d.O.selectOrderbyUserAndIds : ==> Parameters: 1037479531180457984(Long), 2(Long)
2024-09-02 21:42:30.867 INFO 16652 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-02 21:42:30.869 INFO 16652 --- [ main] ShardingSphere-SQL : Logic SQL: select * from t_order t where t.order_id in ( ? ) and user_id = ?
2024-09-02 21:42:30.869 INFO 16652 --- [ main] ShardingSphere-SQL : SQLStatement: SelectStatement(super=DQLStatement(super=AbstractSQLStatement(type=DQL, tables=Tables(tables=[Table(name=t_order, alias=Optional.of(t))]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[Condition(column=Column(name=order_id, tableName=t_order), operator=IN, compareOperator=null, positionValueMap={}, positionIndexMap={0=0}), Condition(column=Column(name=user_id, tableName=t_order), operator=EQUAL, compareOperator==, positionValueMap={}, positionIndexMap={0=1})])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_order, quoteCharacter=NONE, schemaNameLength=0)], parametersIndex=2, logicSQL=select * from t_order t where t.order_id in ( ? ) and user_id = ?)), containStar=true, firstSelectItemStartIndex=7, selectListStopIndex=7, groupByLastIndex=0, items=[StarSelectItem(owner=Optional.absent())], groupByItems=[], orderByItems=[], limit=null, subqueryStatement=null, subqueryStatements=[], subqueryConditions=[])
2024-09-02 21:42:30.869 INFO 16652 --- [ main] ShardingSphere-SQL : Actual SQL: m1 ::: select * from t_order_1 t where t.order_id in ( ? ) and user_id = ? ::: [1037479531180457984, 2]
2024-09-02 21:42:30.895 DEBUG 16652 --- [ main] c.i.d.s.d.O.selectOrderbyUserAndIds : <== Total: 1
查询条件user_id为2,根据分片策略m$->{user_id % 2 + 1}计算得出m1,此sharding-jdbc将sql路由到m1。
总结
当使用user_id查询时,因为分库策略中以user_id为分片键,所以会在user_id为偶数操作m1数据源,又根据当查询偶数结尾的id时,根据t_order表的分片策略使用t_order_1表。所以结果为使用m1库中t_order_1表查询。
在分库分表中查条件查询时,能加上分片的字段就一定要加上查询,没有分片键时会广播路由,查询所有的数据源。
二、公共表
公共表属于系统中数据量较小,变动少,而且属于高频联合查询的依赖表。参数表、数据字典表等属于此类型。可以将这类表在每个数据库都保存一份,所有更新操作都同时发送到所有分库执行。接下来看一下如何使用Sharding-JDBC实现公共表。
1. 创建数据库
分别在user_db、order_db_1、order_db_2中创建t_dict表:
CREATE TABLE `t_user` (`user_id` bigint NOT NULL COMMENT '用户id',`fullname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户姓名',`user_type` char(1) DEFAULT NULL COMMENT '用户类型',PRIMARY KEY (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC;CREATE TABLE `t_dict` (
`dict_id` bigint(20) NOT NULL COMMENT '字典id',
`type` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典类型',
`code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典编码',
`value` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典值',
PRIMARY KEY (`dict_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
2. 在Sharding-JDBC规则中修改
# 指定t_dict为公共表
spring.shardingsphere.sharding.broadcast‐tables=t_dict
完整配置
server.port=8889spring.application.name = sharding-jdbc-simple-demoserver.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = truespring.main.allow-bean-definition-overriding = truemybatis.configuration.map-underscore-to-camel-case = true#sharding-jdbc分片规则配置
#数据源
spring.shardingsphere.datasource.names = m1,m2,m0spring.shardingsphere.datasource.m0.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m0.url = jdbc:mysql://localhost:3308/user_db?useUnicode=true
spring.shardingsphere.datasource.m0.username = root
spring.shardingsphere.datasource.m0.password = 123456spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url = jdbc:mysql://localhost:3308/order_db_1?useUnicode=true
spring.shardingsphere.datasource.m1.username = root
spring.shardingsphere.datasource.m1.password = 123456spring.shardingsphere.datasource.m2.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m2.url = jdbc:mysql://localhost:3308/order_db_2?useUnicode=true
spring.shardingsphere.datasource.m2.username = root
spring.shardingsphere.datasource.m2.password = 123456# 分库策略,以user_id为分片键,分片策略为user_id % 2 + 1,user_id为偶数操作m1数据源,否则操作m2。
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column = user_id
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression = m$->{user_id % 2 + 1}# 指定t_order表的数据分布情况,配置数据节点 m.t_order_1,m1.t_order_2,m2.t_order_1,m2.t_order_21
# 如果这里配置如m1.t_order_$->{1..2},则查询时只会查询m1库的表
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m$->{1..2}.t_order_$->{1..2}
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes = m$->{0}.t_user# 指定t_order表的主键生成策略为SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE# 指定t_order表的分片策略,分片策略包括分片键和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 2 + 1}spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column = user_id
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression = t_user# 指定t_dict为公共表
spring.shardingsphere.sharding.broadcast‐tables=t_dict# 打开sql输出日志
spring.shardingsphere.props.sql.show = trueswagger.enable = truelogging.level.root = info
logging.level.org.springframework.web = info
logging.level.com.itheima.dbsharding = debug
logging.level.druid.sql = debug
3. 数据操作
新增DictDao:
@Mapper
@Component
public interface DictDao {
/**
* 新增字典
* @param type 字典类型
* @param code 字典编码
* @param value 字典值
* @return
*/
@Insert("insert into t_dict(dict_id,type,code,value) value(#{dictId},#{type},#{code},#{value})")
int insertDict(@Param("dictId") Long dictId,@Param("type") String type, @Param("code")String code, @Param("value")String value);
/**
* 删除字典
* @param dictId 字典id
* @return
*/
@Delete("delete from t_dict where dict_id = #{dictId}")
int deleteDict(@Param("dictId") Long dictId);
}
4. 字典操作测试
新增单元测试方法:
@Test
public void testInsertDict(){//t_dict设置为公共表后,插入数据时会同时插入所有数据源dictDao.insertDict(1L,"user_type","1","超级管理员");dictDao.insertDict(2L,"user_type","2","二级管理员");
}
输出
2024-09-02 22:19:45.760 DEBUG 8620 --- [ main] c.i.d.simple.dao.DictDao.insertDict : ==> Preparing: insert into t_dict(dict_id,type,code,value) value(?,?,?,?)
2024-09-02 22:19:45.774 DEBUG 8620 --- [ main] c.i.d.simple.dao.DictDao.insertDict : ==> Parameters: 1(Long), user_type(String), 1(String), 超级管理员(String)
2024-09-02 22:19:46.148 INFO 8620 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-02 22:19:46.149 INFO 8620 --- [ main] ShardingSphere-SQL : Logic SQL: insert into t_dict(dict_id,type,code,value) value(?,?,?,?)
2024-09-02 22:19:46.149 INFO 8620 --- [ main] ShardingSphere-SQL : SQLStatement: InsertStatement(super=DMLStatement(super=AbstractSQLStatement(type=DML, tables=Tables(tables=[Table(name=t_dict, alias=Optional.absent())]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_dict, quoteCharacter=NONE, schemaNameLength=0), SQLToken(startIndex=18)], parametersIndex=4, logicSQL=insert into t_dict(dict_id,type,code,value) value(?,?,?,?)), deleteStatement=false, updateTableAlias={}, updateColumnValues={}, whereStartIndex=0, whereStopIndex=0, whereParameterStartIndex=0, whereParameterEndIndex=0), columnNames=[dict_id, type, code, value], values=[InsertValue(columnValues=[org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@74d6736, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@52a33c3f, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@668625f5, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@19a20bb2])])
2024-09-02 22:19:46.150 INFO 8620 --- [ main] ShardingSphere-SQL : Actual SQL: m0 ::: insert into t_dict (dict_id, type, code, value) VALUES (?, ?, ?, ?) ::: [1, user_type, 1, 超级管理员]
2024-09-02 22:19:46.150 INFO 8620 --- [ main] ShardingSphere-SQL : Actual SQL: m1 ::: insert into t_dict (dict_id, type, code, value) VALUES (?, ?, ?, ?) ::: [1, user_type, 1, 超级管理员]
2024-09-02 22:19:46.150 INFO 8620 --- [ main] ShardingSphere-SQL : Actual SQL: m2 ::: insert into t_dict (dict_id, type, code, value) VALUES (?, ?, ?, ?) ::: [1, user_type, 1, 超级管理员]
2024-09-02 22:19:46.220 DEBUG 8620 --- [ main] c.i.d.simple.dao.DictDao.insertDict : <== Updates: 1
2024-09-02 22:19:46.225 DEBUG 8620 --- [ main] c.i.d.simple.dao.DictDao.insertDict : ==> Preparing: insert into t_dict(dict_id,type,code,value) value(?,?,?,?)
2024-09-02 22:19:46.225 DEBUG 8620 --- [ main] c.i.d.simple.dao.DictDao.insertDict : ==> Parameters: 2(Long), user_type(String), 2(String), 二级管理员(String)
2024-09-02 22:19:46.226 INFO 8620 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-02 22:19:46.226 INFO 8620 --- [ main] ShardingSphere-SQL : Logic SQL: insert into t_dict(dict_id,type,code,value) value(?,?,?,?)
2024-09-02 22:19:46.226 INFO 8620 --- [ main] ShardingSphere-SQL : SQLStatement: InsertStatement(super=DMLStatement(super=AbstractSQLStatement(type=DML, tables=Tables(tables=[Table(name=t_dict, alias=Optional.absent())]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_dict, quoteCharacter=NONE, schemaNameLength=0), SQLToken(startIndex=18)], parametersIndex=4, logicSQL=insert into t_dict(dict_id,type,code,value) value(?,?,?,?)), deleteStatement=false, updateTableAlias={}, updateColumnValues={}, whereStartIndex=0, whereStopIndex=0, whereParameterStartIndex=0, whereParameterEndIndex=0), columnNames=[dict_id, type, code, value], values=[InsertValue(columnValues=[org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@74d6736, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@52a33c3f, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@668625f5, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@19a20bb2])])
2024-09-02 22:19:46.226 INFO 8620 --- [ main] ShardingSphere-SQL : Actual SQL: m0 ::: insert into t_dict (dict_id, type, code, value) VALUES (?, ?, ?, ?) ::: [2, user_type, 2, 二级管理员]
2024-09-02 22:19:46.226 INFO 8620 --- [ main] ShardingSphere-SQL : Actual SQL: m1 ::: insert into t_dict (dict_id, type, code, value) VALUES (?, ?, ?, ?) ::: [2, user_type, 2, 二级管理员]
2024-09-02 22:19:46.226 INFO 8620 --- [ main] ShardingSphere-SQL : Actual SQL: m2 ::: insert into t_dict (dict_id, type, code, value) VALUES (?, ?, ?, ?) ::: [2, user_type, 2, 二级管理员]
2024-09-02 22:19:46.232 DEBUG 8620 --- [ main] c.i.d.simple.dao.DictDao.insertDict : <== Updates: 1
通过日志可以看出,对t_dict的表的操作被广播至所有数据源。
测试删除字典,观察是否把所有数据源中该 公共表的记录删除。
@Test
public void testDeleteDict(){//删除公共表同理dictDao.deleteDict(2L);
}
输出
2024-09-02 22:21:37.006 DEBUG 8464 --- [ main] c.i.d.simple.dao.DictDao.deleteDict : ==> Preparing: delete from t_dict where dict_id = ?
2024-09-02 22:21:37.026 DEBUG 8464 --- [ main] c.i.d.simple.dao.DictDao.deleteDict : ==> Parameters: 2(Long)
2024-09-02 22:21:37.366 INFO 8464 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-02 22:21:37.367 INFO 8464 --- [ main] ShardingSphere-SQL : Logic SQL: delete from t_dict where dict_id = ?
2024-09-02 22:21:37.367 INFO 8464 --- [ main] ShardingSphere-SQL : SQLStatement: DMLStatement(super=AbstractSQLStatement(type=DML, tables=Tables(tables=[Table(name=t_dict, alias=Optional.absent())]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_dict, quoteCharacter=NONE, schemaNameLength=0)], parametersIndex=1, logicSQL=delete from t_dict where dict_id = ?), deleteStatement=true, updateTableAlias={t_dict=t_dict}, updateColumnValues={}, whereStartIndex=19, whereStopIndex=35, whereParameterStartIndex=0, whereParameterEndIndex=0)
2024-09-02 22:21:37.367 INFO 8464 --- [ main] ShardingSphere-SQL : Actual SQL: m0 ::: delete from t_dict where dict_id = ? ::: [2]
2024-09-02 22:21:37.367 INFO 8464 --- [ main] ShardingSphere-SQL : Actual SQL: m1 ::: delete from t_dict where dict_id = ? ::: [2]
2024-09-02 22:21:37.367 INFO 8464 --- [ main] ShardingSphere-SQL : Actual SQL: m2 ::: delete from t_dict where dict_id = ? ::: [2]
2024-09-02 22:21:37.425 DEBUG 8464 --- [ main] c.i.d.simple.dao.DictDao.deleteDict : <== Updates: 1
5. 字典关联查询测试
字典表已在各各分库存在,各业务表即可和字典表关联查询。
定义用户关联查询dao
在UserDao中定义:
/*** 根据id列表查询多个用户* @param userIds 用户id列表* @return*/
@Select({"<script>"," select"," * "," from t_user t ,t_dict b"," where t.user_type = b.code and t.user_id in","<foreach collection='userIds' item='id' open='(' separator=',' close=')'>","#{id}","</foreach>","</script>"
})
List<Map> selectUserInfobyIds(@Param("userIds") List<Long> userIds);
测试方法:
@Test
public void testSelectUserInfobyIds(){//分库的表可以直接在库中关联查询公共表List<Long> userIds = new ArrayList<>();userIds.add(11L);userIds.add(12L);List<Map> users = userDao.selectUserInfobyIds(userIds);System.out.println(users);
}
输出
2024-09-02 22:22:53.729 DEBUG 22356 --- [ main] c.i.d.s.dao.UserDao.selectUserInfobyIds : ==> Preparing: select * from t_user t ,t_dict b where t.user_type = b.code and t.user_id in ( ? , ? )
2024-09-02 22:22:53.743 DEBUG 22356 --- [ main] c.i.d.s.dao.UserDao.selectUserInfobyIds : ==> Parameters: 11(Long), 12(Long)
2024-09-02 22:22:54.081 INFO 22356 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-02 22:22:54.083 INFO 22356 --- [ main] ShardingSphere-SQL : Logic SQL: select * from t_user t ,t_dict b where t.user_type = b.code and t.user_id in ( ? , ? )
2024-09-02 22:22:54.083 INFO 22356 --- [ main] ShardingSphere-SQL : SQLStatement: SelectStatement(super=DQLStatement(super=AbstractSQLStatement(type=DQL, tables=Tables(tables=[Table(name=t_user, alias=Optional.of(t)), Table(name=t_dict, alias=Optional.of(b))]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[Condition(column=Column(name=user_id, tableName=t_user), operator=IN, compareOperator=null, positionValueMap={}, positionIndexMap={0=0, 1=1})])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_user, quoteCharacter=NONE, schemaNameLength=0), TableToken(tableName=t_dict, quoteCharacter=NONE, schemaNameLength=0)], parametersIndex=2, logicSQL=select * from t_user t ,t_dict b where t.user_type = b.code and t.user_id in ( ? , ? ))), containStar=true, firstSelectItemStartIndex=8, selectListStopIndex=8, groupByLastIndex=0, items=[StarSelectItem(owner=Optional.absent())], groupByItems=[], orderByItems=[], limit=null, subqueryStatement=null, subqueryStatements=[], subqueryConditions=[])
2024-09-02 22:22:54.083 INFO 22356 --- [ main] ShardingSphere-SQL : Actual SQL: m0 ::: select * from t_user t ,t_dict b where t.user_type = b.code and t.user_id in ( ? , ? ) ::: [11, 12]
2024-09-02 22:22:54.120 DEBUG 22356 --- [ main] c.i.d.s.dao.UserDao.selectUserInfobyIds : <== Total: 2
[{dict_id=1, user_type=1, code=1, user_id=11, fullname=姓名11, type=user_type, value=超级管理员}, {dict_id=1, user_type=1, code=1, user_id=12, fullname=姓名12, type=user_type, value=超级管理员}]
总结分库分表配置大概流程:
- 先配置数据源
- 是否分库,是则配置分库策略
- 必须配置数据节点
- 是否要配置主键生成策略
- 配置每个表的分片策略
三、读写分离
1.理解读写分离
MySQL的读写分离是一种常见的数据库架构模式,用于提高数据库的可用性和扩展性。通过将读取请求分散到多个从服务器(slave servers),可以减轻主服务器(master server)的负载,从而提高读取性能。同时,写入请求仍然集中在一个主服务器上执行,保证了数据的一致性和完整性。

面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。

通过一主多从的配置方式,可以将查询请求均匀的分散到多个数据副本,能够进一步的提升系统的处理能力。 使用多主多从的方式,不但能够提升系统的吞吐量,还能够提升系统的可用性,可以达到在任何一个数据库宕机,甚至磁盘物理损坏的情况下仍然不影响系统的正常运行。

读写分离的数据节点中的数据内容是一致的,而水平分片的每个数据节点的数据内容却并不相同。将水平分片和读写分离联合使用,能够更加有效的提升系统的性能。
Sharding-JDBC读写分离则是根据SQL语义的分析,将读操作和写操作分别路由至主库与从库。它提供透明化读写分离,让使用方尽量像使用一个数据库一样使用主从数据库集群。

Sharding-JDBC提供一主多从的读写分离配置,可独立使用,也可配合分库分表使用,同一线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性。Sharding-JDBC不提供主从数据库的数据同步功能,需要采用其他机制支持。

接下来,咱们对上面例子中user_db进行读写分离实现。为了实现Sharding-JDBC的读写分离,首先,要进行mysql的主从同步配置。
配置mysql主从同步可以看这篇文章:Windows环境下搭建MySQL主从同步实现读写分离
2.实现sharding-jdbc读写分离
1. 在Sharding-JDBC规则中修改
server.port=56081spring.application.name = sharding-jdbc-simple-demoserver.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = truespring.main.allow-bean-definition-overriding = truemybatis.configuration.map-underscore-to-camel-case = true#sharding-jdbc分片规则配置
#数据源
spring.shardingsphere.datasource.names = m1,m2,m0,s0spring.shardingsphere.datasource.m0.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m0.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m0.url = jdbc:mysql://localhost:3308/user_db?useUnicode=true
spring.shardingsphere.datasource.m0.username = root
spring.shardingsphere.datasource.m0.password = 123456spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url = jdbc:mysql://localhost:3308/order_db_1?useUnicode=true
spring.shardingsphere.datasource.m1.username = root
spring.shardingsphere.datasource.m1.password = 123456spring.shardingsphere.datasource.m2.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m2.url = jdbc:mysql://localhost:3308/order_db_2?useUnicode=true
spring.shardingsphere.datasource.m2.username = root
spring.shardingsphere.datasource.m2.password = 123456spring.shardingsphere.datasource.s0.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.s0.driver‐class‐name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.s0.url = jdbc:mysql://localhost:3309/user_db?useUnicode=true
spring.shardingsphere.datasource.s0.username = root
spring.shardingsphere.datasource.s0.password = 123456# 主库从库逻辑数据源定义 ds0为user_db
spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m0
spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names=s0# 分库策略,以user_id为分片键,分片策略为user_id % 2 + 1,user_id为偶数操作m1数据源,否则操作m2。
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column = user_id
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression = m$->{user_id % 2 + 1}# 指定t_order表的数据分布情况,配置数据节点 m.t_order_1,m1.t_order_2,m2.t_order_1,m2.t_order_21
# 如果这里配置如m1.t_order_$->{1..2},则查询时只会查询m1库的表
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m$->{1..2}.t_order_$->{1..2}
#spring.shardingsphere.sharding.tables.t_user.actual-data-nodes = m$->{0}.t_user
# t_user分表策略,固定分配至ds0的t_user真实表
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes = ds0.t_user# 指定t_order表的主键生成策略为SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE# 指定t_order表的分片策略,分片策略包括分片键和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 2 + 1}spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.sharding-column = user_id
spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithm-expression = t_user# 指定t_dict为公共表
spring.shardingsphere.sharding.broadcast‐tables=t_dict# 打开sql输出日志
spring.shardingsphere.props.sql.show = trueswagger.enable = truelogging.level.root = info
logging.level.org.springframework.web = info
logging.level.com.itheima.dbsharding = debug
logging.level.druid.sql = debug...
- 测试
执行testInsertUser单元测试:
@Test
public void testInsertUser2() {userDao.insertUser(16L, "姓名" + 16);//插入时在m0(主库)中
}
输出
2024-09-24 07:27:54.672 DEBUG 25836 --- [ main] c.i.d.simple.dao.UserDao.insertUser : ==> Preparing: insert into t_user(user_id, fullname) value(?,?)
2024-09-24 07:27:54.690 DEBUG 25836 --- [ main] c.i.d.simple.dao.UserDao.insertUser : ==> Parameters: 16(Long), 姓名16(String)
2024-09-24 07:27:55.055 INFO 25836 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-24 07:27:55.056 INFO 25836 --- [ main] ShardingSphere-SQL : Logic SQL: insert into t_user(user_id, fullname) value(?,?)
2024-09-24 07:27:55.056 INFO 25836 --- [ main] ShardingSphere-SQL : SQLStatement: InsertStatement(super=DMLStatement(super=AbstractSQLStatement(type=DML, tables=Tables(tables=[Table(name=t_user, alias=Optional.absent())]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[Condition(column=Column(name=user_id, tableName=t_user), operator=EQUAL, compareOperator=null, positionValueMap={}, positionIndexMap={0=0})])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_user, quoteCharacter=NONE, schemaNameLength=0), SQLToken(startIndex=18)], parametersIndex=2, logicSQL=insert into t_user(user_id, fullname) value(?,?)), deleteStatement=false, updateTableAlias={}, updateColumnValues={}, whereStartIndex=0, whereStopIndex=0, whereParameterStartIndex=0, whereParameterEndIndex=0), columnNames=[user_id, fullname], values=[InsertValue(columnValues=[org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@3e36b7a0, org.apache.shardingsphere.core.parse.old.parser.expression.SQLPlaceholderExpression@60c1663c])])
2024-09-24 07:27:55.056 INFO 25836 --- [ main] ShardingSphere-SQL : Actual SQL: m0 ::: insert into t_user (user_id, fullname) VALUES (?, ?) ::: [16, 姓名16]
2024-09-24 07:27:55.080 DEBUG 25836 --- [ main] c.i.d.simple.dao.UserDao.insertUser : <== Updates: 1
可以发现插入时在m0(主库)中
通过日志可以看出,所有写操作落入m0数据源。
执行testSelectUserbyIds单元测试:
@Test
public void testSelectUserInfobyIds2() {//分库的表可以直接在库中关联查询公共表List<Long> userIds = new ArrayList<>();userIds.add(16L);List<Map> users = userDao.selectUserInfobyIds(userIds);System.out.println(users);//查询时在s0(从库)中
}
输出
2024-09-24 07:29:46.292 DEBUG 4776 --- [ main] c.i.d.s.dao.UserDao.selectUserInfobyIds : ==> Preparing: select * from t_user t ,t_dict b where t.user_type = b.code and t.user_id in ( ? )
2024-09-24 07:29:46.310 DEBUG 4776 --- [ main] c.i.d.s.dao.UserDao.selectUserInfobyIds : ==> Parameters: 16(Long)
2024-09-24 07:29:46.653 INFO 4776 --- [ main] ShardingSphere-SQL : Rule Type: sharding
2024-09-24 07:29:46.656 INFO 4776 --- [ main] ShardingSphere-SQL : Logic SQL: select * from t_user t ,t_dict b where t.user_type = b.code and t.user_id in ( ? )
2024-09-24 07:29:46.656 INFO 4776 --- [ main] ShardingSphere-SQL : SQLStatement: SelectStatement(super=DQLStatement(super=AbstractSQLStatement(type=DQL, tables=Tables(tables=[Table(name=t_user, alias=Optional.of(t)), Table(name=t_dict, alias=Optional.of(b))]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[AndCondition(conditions=[Condition(column=Column(name=user_id, tableName=t_user), operator=IN, compareOperator=null, positionValueMap={}, positionIndexMap={0=0})])])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=t_user, quoteCharacter=NONE, schemaNameLength=0), TableToken(tableName=t_dict, quoteCharacter=NONE, schemaNameLength=0)], parametersIndex=1, logicSQL=select * from t_user t ,t_dict b where t.user_type = b.code and t.user_id in ( ? ))), containStar=true, firstSelectItemStartIndex=8, selectListStopIndex=8, groupByLastIndex=0, items=[StarSelectItem(owner=Optional.absent())], groupByItems=[], orderByItems=[], limit=null, subqueryStatement=null, subqueryStatements=[], subqueryConditions=[])
2024-09-24 07:29:46.656 INFO 4776 --- [ main] ShardingSphere-SQL : Actual SQL: s0 ::: select * from t_user t ,t_dict b where t.user_type = b.code and t.user_id in ( ? ) ::: [16]
2024-09-24 07:29:46.694 DEBUG 4776 --- [ main] c.i.d.s.dao.UserDao.selectUserInfobyIds : <== Total: 1
[{dict_id=2, user_type=1, code=1, user_id=16, fullname=姓名16, type=order_type, value=1}]
通过日志可以看出,所有查询操作落入s0数据源,达到目标。
相关文章:
Sharding-JDBC笔记03-分库分表代码示例
文章目录 一、水平分库1. 将原有order_db库拆分为order_db_1、order_db_22. 分片规则修改分片策略standardcomplexinlinehintnone 3. 插入测试4. 查询测试5. 使用分库分片键查询测试总结 二、公共表1. 创建数据库2. 在Sharding-JDBC规则中修改3. 数据操作4. 字典操作测试5. 字典…...
气膜健身馆:提升运动体验与健康的理想选择—轻空间
近年来,气膜健身馆作为一种新兴的运动场所,正逐渐受到越来越多健身爱好者的青睐。这种独特的建筑形式不仅提供了良好的运动环境,更在健康和运动表现上展现出诸多优势。 优越的空气质量 气膜结构的核心技术通过内外气压差形成稳定的气膜&#…...
选择更轻松:山海鲸可视化与PowerBI的深度对比
在数据分析与可视化的时代,选择合适的报表工具显得尤为重要。山海鲸可视化和PowerBI是市场上颇受欢迎的两款免费报表软件,各有特色。接下来,我们将从功能、优缺点等方面进行对比,帮助你找到最适合的工具。 山海鲸可视化 山海鲸可…...
Python Daphne库:ASGI服务的高效Web服务器
更多Python学习内容:ipengtao.com 随着 Web 开发技术的不断发展,异步编程逐渐成为构建高性能 Web 应用的主流方式。传统的 WSGI 接口已经不能满足现代异步 Web 应用的需求。ASGI(Asynchronous Server Gateway Interface)作为 WSGI…...
如何保护自己电脑以及服务器的ip地址
保护你的电脑和服务器的IP地址,可以采取以下措施: 1. 使用代理服务器 HTTP/HTTPS代理:通过代理服务器访问网络,隐藏真实IP地址。SOCKS代理:提供更高级的网络流量转发,可以更好地处理各种网络协议。 2. 配…...
我的创作纪念日---256days
机缘 1.总结自己的学习过程面遇到的困难的解决方案; 2.总结自己日常学习过程中的知识,以及自己的理解和看法; 3.帮助需要的小伙伴在自己的文章里面找到想要的答案; 4.共同推进CSDN社区建设; 5.让自己每天都去写博…...
前端大模型入门:Transformer.js 和 Xenova-引领浏览器端的机器学习变革
除了调用别人的api接口使用transformer技术,你是否想过将大模型在浏览器中运行呢?尤其是WebGPU的出现,性能比WebGL高不少,很多小任务真的不再需要在一个中心运行了。 不少同学买课学python了,但我还是在坚持用js尝试&a…...
计算机性能指标之MFLOPS
1. MFLOPS的定义与计算方式 定义:MFLOPS,全称Million Floating-point Operations Per Second,即每秒百万次浮点运算,是衡量计算机系统浮点运算能力的一个重要技术指标。 计算方式:MFLOPS的计算公式为“浮点操作次数 /…...
Sharp.js:简单而又实用的图像处理库
前言 在现代Web开发中,图像处理是一个不可或缺的部分。 前端开发者经常需要处理图像,以确保它们在不同的设备和分辨率上都能保持良好的显示效果。 sharp.js是一个高性能的Node.js模块,它利用了libvips库,提供了快速且高效的图像…...
Rust环境安装配置
要加速安装 Rust 和 git-cliff,可以配置国内的镜像源。特别是在国内访问 Rust 官方的安装源时,可能会遇到速度较慢的问题。通过配置 TUNA(清华大学开源软件镜像站)的镜像源,可以大幅提升安装速度。 1. 配置国内镜像加…...
衡石分析平台系统管理手册-功能配置之全局 JS 设置
全局 JS 设置 衡石系统提供了全局 JS 设置功能,用户可以通过自定义 JS 代码实现系统的个性化需求,如使用第三方统计工具对系统平台的 PV 、UV 进行监测。 使用场景 场景1:增加百度统计 下图示例中使用 js 代码引用了百度网站统计功…...
OpenHarmony(鸿蒙南向)——平台驱动开发【MIPI DSI】
往期知识点记录: 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~ 持续更新中…… 概述 功能简介 DSI(Display Serial Interface&#x…...
C++_一篇文章让你弄懂各类(运算符)
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 内置了丰富的运算符,并提供了以下类型的运算符: 算术运算符关系运算符逻辑运算符位运算符赋值运算符杂项运算符 本章将逐一介绍算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和…...
顺序表算法题 —— 移除元素、删除有序数组中的重复项、合并两个有序数组
目录 一、顺序表算法题 1、移除元素 2、删除有序数组中的重复项 3、 合并两个有序数组 二、顺序表问题与思考 一、顺序表算法题 1、移除元素 移除元素 - 力扣(LeetCode) 思路分析: 思路一:创建一个新数组,开辟…...
配置ssh后又报错git@github.com: Permission denied (publickey)
再添加一次ssh有用 ssh-add ~/.ssh/你的id_rsa的名字可以先运行 eval "$(ssh-agent -s)"再添加,Jesus每次重启terminal都要输入一遍 报错 gitgithub.com: Permission denied (publickey) 通常是由于 SSH 公钥没有正确配置或者 GitHub 上未能识别你的公钥…...
yolov10安装体验
按照官网 conda create -n yolov10 python=3.9 conda activate yolov10 pip install -r requirements.txt pip install -e . 一路安装,运行yolov10的问题,初次接触的同学可以注意。 Set arbitrary_types_allowed=True in the model_config to ignore this error f you got th…...
使用Docker-Compose部署SpringBoot项目的案例
Docker-Compose是Docker官方的一个开源项目,主要用于实现对Docker容器集群的快速编排和管理。该项目由Python编写,通过调用Docker服务提供的API来管理容器。只要所操作的平台支持Docker API,就可以利用Docker-Compose进行编排管理。Docker-Co…...
大话 RCU (read copy update)
还得是看官方文档。kernel/Document/RCU/WhatisRCU.rst. 首先,我们要搞清楚一件事,指针它是一个变量,他在内存上也是占了空间的,然后他里面的值,是你申请的内存块的首地址。文档开篇就讲咱们的基本原理,就…...
vue项目npm run serve 报错,Error: read ECONNRESET at TCP.onStreamRead
背景:vue2的项目,之前npm run serve一直可以正常使用,突然每次启动都会报错了,报错信息如下: node:events:492 throw er; // Unhandled error event ^ Error: read ECONNRESET at TCP.onStreamRead (n…...
十二、MySQL数据类型精讲
文章目录 1. MySQL中的数据类型2. 整数类型2.1 类型介绍2.2 可选属性2.2.1 M2.2.2 UNSIGNED2.2.3 ZEROFILL 2.3 适用场景2.4 如何选择? 3. 浮点类型3.1 类型介绍3.2 数据精度说明3.3 精度误差说明 4. 定点数类型4.1 类型介绍4.2 开发中经验 5. 位类型:BI…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
QT开发技术【ffmpeg + QAudioOutput】音乐播放器
一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下,音视频内容犹如璀璨繁星,点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频,到在线课堂中知识渊博的专家授课,再到影视平台上扣人心弦的高清大片,音…...
