Sharding-JDBC笔记03-分库分表代码示例

news2024/9/28 14:19:45

文章目录

  • 一、水平分库
    • 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=8889

spring.application.name = sharding-jdbc-simple-demo

server.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = true

spring.main.allow-bean-definition-overriding = true

mybatis.configuration.map-underscore-to-camel-case = true

#sharding-jdbc分片规则配置
#数据源
spring.shardingsphere.datasource.names = m1,m2


spring.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 = 123456

spring.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 = true

swagger.enable = true

logging.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时

    @Test
    public 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);
}

编写测试方法:

    @Test
    public 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=8889

spring.application.name = sharding-jdbc-simple-demo

server.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = true

spring.main.allow-bean-definition-overriding = true

mybatis.configuration.map-underscore-to-camel-case = true

#sharding-jdbc分片规则配置
#数据源
spring.shardingsphere.datasource.names = m1,m2,m0

spring.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 = 123456

spring.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 = 123456

spring.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 = true

swagger.enable = true

logging.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. 先配置数据源
  2. 是否分库,是则配置分库策略
  3. 必须配置数据节点
  4. 是否要配置主键生成策略
  5. 配置每个表的分片策略

三、读写分离

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=56081

spring.application.name = sharding-jdbc-simple-demo

server.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = true

spring.main.allow-bean-definition-overriding = true

mybatis.configuration.map-underscore-to-camel-case = true

#sharding-jdbc分片规则配置
#数据源
spring.shardingsphere.datasource.names = m1,m2,m0,s0

spring.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 = 123456

spring.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 = 123456

spring.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

spring.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 = true

swagger.enable = true

logging.level.root = info
logging.level.org.springframework.web = info
logging.level.com.itheima.dbsharding  = debug
logging.level.druid.sql = debug


...

  1. 测试
    执行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数据源,达到目标。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2173772.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux线程-POSIX信号量与锁以及条件变量

POSIX信号量 POSIX没有元素这个概念相比于SYSTEM-V更简洁&#xff0c;POSIX不一定适用老版本&#xff1b;二者都是系统范畴&#xff0c;都需要手动删除&#xff0c;POSIX相关函数属于线程库&#xff0c;所有编译时需要末尾加上-lpthread选项 POSIX POSIX有名信号量 主要用于进…

华为 HCIP-Datacom H12-821 题库 (29)

&#x1f423;博客最下方微信公众号回复题库,领取题库和教学资源 &#x1f424;诚挚欢迎IT交流有兴趣的公众号回复交流群 &#x1f998;公众号会持续更新网络小知识&#x1f63c; 1.BFD 为确保两端系统都知道状态的变化&#xff0c;在BFD 状态机的建立和拆除时都采用三次握手…

【LeetCode:75. 颜色分类 + 快速排序】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

图像超分辨率(SR)

图像超分辨率&#xff08;Image Super-Resolution, SR&#xff09;是一种图像处理技术&#xff0c;旨在从低分辨率&#xff08;LR&#xff09;图像中恢复出高分辨率&#xff08;HR&#xff09;图像。这种技术通过增加图像中的细节和清晰度来提高图像的视觉质量&#xff0c;从而…

微信支付准备工作之内网穿透2024/9/28

微信支付部分好像做不了&#xff0c;但是跟着写了点东西。 做项目的微信支付功能时&#xff0c;微信后台需要调用到商户管理系统&#xff0c;但是我们的管理系统写在自己的电脑里。微信后台如何调用到商户系统&#xff1f;内网穿透。 还有如何保证调用过程数据安全&#xff1…

PowerDesigner 16.5安装教程 + 轻松解决软件证书过期导致的无法使用问题

目录 背景: 安装教程 &#xff1a; 证书过期的解决方法&#xff1a; 背景: PowerDesigner16.5凭借强大的功能集成、广泛的兼容性和高效的模型驱动开发方法成为了企业级建模于设计领域的佼佼者。无论是在企业信息化建设、软件开发项目还是数据库设计于管理等领域它都能提有利…

【步联科技身份证】 身份证读取与解析———未来之窗行业应用跨平台架构

一、身份证解析代码 C# function 身份证数据解析_湖南步联科技(wzxx) {var result {};result[xm] wzxx.substr(0, 15);result[xbdm] wzxx.substr(15, 1);result[mzdm] wzxx.substr(16, 2);result[csrq] wzxx.substr(18, 8);result[dzmc] wzxx.substr(26, 35);result[gms…

论文阅读 | HiDDeN网络架构

ECCV 2018 斯坦福-李飞飞团队 一、问题描述 受以下启发&#xff1a; 对抗性例子的发现&#xff1a;深度学习模型在图像识别任务中对微小的、难以察觉的输入扰动非常敏感&#xff0c;这些扰动可以导致模型错误分类图像。这一现象表明&#xff0c;神经网络可以在图像中编码信息&…

一文上手SpringSecurity【五】

对于前后端不分离的项目,我们可以采用一文上手SpringSecurity【四】当中的方式来自定义用户的登录页面和数据源,数据源目前采用的是模拟的方式来实现的,本篇内容主要介绍一下spring security对于前后端分离项目如何实现认证和授权的. 一、前后端分离的认证面对的问题 1.1 传统…

File systems

inode descriptor 文件系统中核心的数据结构就是inode和file descriptor。后者主要与用户进程进行交互。 inode&#xff0c;这是代表一个文件的对象&#xff0c;并且它不依赖于文件名。实际上&#xff0c;inode是通过自身的编号来进行区分的&#xff0c;这里的编号就是个整数…

修改 idea 的 Terminal 命令窗口使用 git-bash

修改配置方法 实际使用效果 &#xff08;END&#xff09;

Java Stream 神技!10招顶级技巧,让你的代码简洁又高效!

哈喽&#xff0c;欢迎来到【程序视点】&#xff0c;我是小二哥。 引言 你是否曾在编写Java代码时&#xff0c;为了处理集合而感到头痛不已&#xff1f;是否在寻找一种更优雅、更简洁的方式来简化你的代码&#xff1f; 如果你的答案是肯定的&#xff0c;那么Java Stream API无…

org.eclipse.paho.client.mqttv3.MqttException: 无效客户机标识

需求背景 最近有一个项目,需要用到阿里云物联网,不是MQ。发现使用原来EMQX的代码去连接阿里云MQTT直接报错,试了很多种方案都不行。最终还是把错误分析和教程都整理一下。 需要注意的是,阿里云物联网平台和MQ不一样。方向别走偏了。 概念描述 EMQX和阿里云MQTT有什么区别…

OpenCV视频I/O(6)检查视频捕获对象是否已成功打开的函数isOpened()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 如果视频捕获已经初始化&#xff0c;则返回 true。 如果之前调用 VideoCapture 构造函数或 VideoCapture::open() 成功&#xff0c;则该方法返回…

ireport 5.1 中文生辟字显示不出来,生成PDF报字体找不到

问题&#xff1a; 情况1&#xff1a;ireport中填入中文生辟字的时候不显示&#xff0c;或者无法输入和粘贴生辟字。 情况2&#xff1a;生成pdf的时候报字体找不到。 net.sf.jasperreports.engine.JRRuntimeException: Could not load the following font : pdfFontName : …

十分钟实现内网连接,配置frp

十分钟实现内网连接&#xff0c;配置frp 一.frp是什么&#xff1f;其实是一款实现外网连接内网的一个工具&#xff0c;个人理解&#xff0c;说白了就像是teamviwer一样&#xff0c;外网能访问内网。 利用处于内网或防火墙后的机器&#xff0c;对外网环境提供 http 或 https 服…

Python神经求解器去耦合算法和瓦瑟斯坦距离量化评估

&#x1f3af;要点 神经求解器求解对偶方程&#xff0c;并学习两个空间之间的单调变换&#xff0c;最小化它们之间的瓦瑟斯坦距离。使用概率密度函数解析计算&#xff0c;神经求解器去耦合条件正则化流使用变量变换公式的生成模型瓦瑟斯坦距离量化评估神经求解器 &#x1f36…

CSS06-元素显示模式、单行文字垂直居中

一、什么是元素显示模式 1-1、块级元素 1-2、行内元素 1-3、行内块元素 1-4、小结 二、元素显示模式转换 三、单行文字垂直居中 CSS 没有给我们提供文字垂直居中的代码&#xff0c;这里我们可以使用一个小技巧来实现。 解决方案: 让文字的行高等于盒子的高度&#xff0c;就可…

普通二叉搜索树的模拟实现【C++】

二叉搜素树简单介绍 二叉搜索树又称二叉排序树&#xff0c;是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值 它的左右子树也分别为二叉搜索树 注意…

C++深入学习string类成员函数(4):字符串的操作

引言 在c中&#xff0c;std::string提供了许多字符串操作符函数&#xff0c;让我们能够秦松驾驭文本数据&#xff0c;而与此同时&#xff0c;非成员函数的重载更是为string类增添了别样的魅力&#xff0c;输入输出流的重载让我们像处理基本类型的数据一样方便地读取和输出字符…