石家庄网站建设外包/域名污染查询网站
文章目录
- 一、水平分库
- 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…...

不同参数对分类精度的影响以及思考
1 问题 探索不同的batch_size对分类精度的影响探索不同的损失函数对分类精度的影响 2 方法 问题一 要知道的是Batch_size的作用:决定了下降的方向。在合理范围内,增大Batch_size的好处: 一是提高了内存利用率以及大矩阵乘法的并行化效率&…...

开源AI智能名片小程序源码:私域电商构建独特竞争力的新机遇
摘要:本文旨在探讨私域电商如何利用开源AI智能名片小程序源码构建独特竞争力。在强调独特性是通向成功的必要条件的基础上,分析开源AI智能名片小程序源码在私域电商发展独特性方面的作用及相关策略。 一、引言 在竞争激烈的商业环境中,让自己…...

从Web2到Web3:探索下一代互联网的无限可能性
互联网经历了从Web1到Web2的重大变革,现在正迈向Web3。Web2通过社交媒体、电子商务和内容平台改变了我们的数字生活,但同时也伴随着中心化平台的垄断和用户数据被广泛控制的问题。而Web3的出现,则试图通过去中心化技术解决这些挑战࿰…...

POE供电支持画中画的摄像头解决方案
首先他的主芯片由嵌入式操作系统和高性能硬件处理平台,具有较高稳定性和可靠性,有丰富的接口,可以支持二次开发定制的. 首先,什么是poe供电呢?Poe供电是通过网络线(网线)供电的一种技术&#x…...

Python 3 字典
Python 3 字典 引言 Python 字典(Dictionary)是一种非常有用的内置数据类型,用于存储键值对。在 Python 3 中,字典保持了一些基本特性,同时也有一些新的改进和特性。本文将详细介绍 Python 3 中的字典,包括其基本操作、常用方法以及一些高级特性。 字典的基本操作 创…...

CFR( Java 反编译器)
一、安装教程 CFR(Class File Reader)是一个流行的Java反编译器,它可以将编译后的.class文件或整个.jar文件转换回Java源代码。以下是CFR的下载和使用教程: 下载CFR 访问CFR的官方网站或GitHub仓库:CFR的最新版本和所…...

单片机的两种看门狗原理解析——IWDG和WWDG
一、IWDG独立开门狗的主要性能 计时机制: 递减计数器 独立开门狗的初始频率: LSI低速内部时钟:RC震荡器,40kHz 独立开门狗是以LSI为初始频率的,所以独立开门狗的初始时钟频率取决与单片机本身,因此在使…...

SQL进阶技巧:如何获取状态一致的分组? | 最大、最小值法
目录 0 需求描述 1 数据准备 2 问题分析 方法1:最大、最小值法(技巧) 方法2:常规思路 3 小结 如果觉得本文对你有帮助,那么不妨也可以选择去看看我的博客专栏 ,部分内容如下: 数字化建设通…...

windows10使用bat脚本安装前后端环境之msyql5.7安装配置并重置用户密码
首先需要搞清楚msyql在本地是怎么安装配置、然后在根据如下步骤编写bat脚本: 思路 1.下载mysql5.7 zip格式安装包 2.新增data文件夹与my.ini配置文件 3.初始化数据库 4.安装mysql windows服务 5.启动并修改root密码(新增用户初始化授予权限)…...

文件上传、amrkdown编辑器
一、文件上传 这里我以图片为例,进行上传,上传到阿里云oss(对象存在中) 首先,我们先梳理一下,图片上传的流程 1、前端选择文件,提交文件 前端提交文件,我们可以使用ElementUI中的…...