【分库分表】sharding-jdbc实践—分库分表入门

一、准备工作

1、准备三个数据库:db0、db1、db2

2、每个数据库新建两个订单表:t_order_0、t_order_1

DROP TABLE IF EXISTS `t_order_x`;
CREATE TABLE `t_order_x` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` bigint NOT NULL,
  `order_id` bigint NOT NULL,
  `order_no` varchar(30) NOT NULL,
  `isactive` tinyint NOT NULL DEFAULT ‘1‘,
  `inserttime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updatetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

二、分库分表配置

数据源的配置可以使用任何链接池,本例用druid为例。

1、引言依赖包:

引用最新的maven包

<sharding-jdbc.version>2.0.1</sharding-jdbc.version>

<dependency>  <groupId>io.shardingjdbc</groupId>  <artifactId>sharding-jdbc-core</artifactId>  <version>${sharding-jdbc.version}</version></dependency>

2、配置DataSource:

    @Bean(name = "shardingDataSource", destroyMethod = "close")
    @Qualifier("shardingDataSource")
    public DataSource getShardingDataSource() {
        // 配置真实数据源
        Map<String, DataSource> dataSourceMap = new HashMap<>(3);

        // 配置第一个数据源
        DruidDataSource dataSource1 = createDefaultDruidDataSource();
        dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource1.setUrl("jdbc:mysql://localhost:3306/db0");
        dataSource1.setUsername("root");
        dataSource1.setPassword("root");
        dataSourceMap.put("db0", dataSource1);

        // 配置第二个数据源
        DruidDataSource dataSource2 = createDefaultDruidDataSource();
        dataSource2.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource2.setUrl("jdbc:mysql://localhost:3306/db1");
        dataSource2.setUsername("root");
        dataSource2.setPassword("root");
        dataSource2.setName("db1-0001");
        dataSourceMap.put("db1", dataSource2);

        // 配置第三个数据源
        DruidDataSource dataSource3 = createDefaultDruidDataSource();
        dataSource3.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource3.setUrl("jdbc:mysql://localhost:3306/db2");
        dataSource3.setUsername("root");
        dataSource3.setPassword("root");
        dataSourceMap.put("db2", dataSource3);

        // 配置Order表规则
        TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
        orderTableRuleConfig.setLogicTable("t_order");
        orderTableRuleConfig.setActualDataNodes("db${0..2}.t_order_${0..1}");
        //orderTableRuleConfig.setActualDataNodes("db0.t_order_0,db0.t_order_1,db1.t_order_0,db1.t_order_1,db2.t_order_0,db2.t_order_1");

        // 配置分库策略(Groovy表达式配置db规则)
        orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "db${user_id % 3}"));

        // 配置分表策略(Groovy表达式配置表路由规则)
        orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order_${order_id % 2}"));

        // 配置分片规则
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);

        // 配置order_items表规则...

        // 获取数据源对象
        DataSource dataSource = null;
        try {
            dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, new ConcurrentHashMap(), new Properties());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

可以使用Druid监控db。

三、示例验证

1、新增数据

@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderMapper orderMapper;

    @RequestMapping("/add")
    public void addOrder() {
        OrderEntity entity10 = new OrderEntity();
        entity10.setOrderId(10000L);
        entity10.setOrderNo("No1000000");
        entity10.setUserId(102333001L);
        orderMapper.insertSelective(entity10);
        OrderEntity entity11 = new OrderEntity();
        entity11.setOrderId(10001L);
        entity11.setOrderNo("No1000000");
        entity11.setUserId(102333000L);
        orderMapper.insertSelective(entity11);
    }
}

依据配置的分片规则

  • DB路由规则:user_id % 3:

     102333001 % 3 = 1

102333000 % 3 = 0

  • 表路由规则:order_id % 2:

10000 % 2 = 0

10001 % 2 = 1

userid=102333001,orderId=10000的数据落地到db1.t_order_0
userid=102333000,orderId=10001的数据落地到db0.t_order_1

2、未指定分片规则字段的查询

    /**广播遍历所有的库和表*/
    @RequestMapping("get")
    public void getOrder() {
        List<Integer> ids = new ArrayList<>();
        ids.add(4);
        List<OrderEntity> orderEntities = orderMapper.selectByPrimaryIds(ids);

        log.info(JSON.toJSONString(orderEntities));
    }

由druid监控sql得知,查询被广播到db0、db1、db2的各个表里,如下监控所示:

3、不能执行批量插入操作

不支持对不同分片规则的字段值进行批量插入操作,类似sql:insert into t_order values(x,x,x,x),(x,x,x,x),(x,x,x,x)

4、谨慎修改分片规则字段

如果修改了分片规则的字段,比如本例的user_id或order_id,因为路由规则会造成数据存在,却查不到数据的情况。

    @RequestMapping("/upd")
    public void update() {
        OrderEntity orderWhere = new OrderEntity();
        orderWhere.setOrderId(10001L);
        orderWhere.setUserId(102333001L);
        orderWhere.setId(4L);

        OrderEntity orderSet = new OrderEntity();
        orderSet.setOrderId(10002L);
        orderSet.setOrderNo("修改订单号");

        orderMapper.updateByPredicate(orderSet, orderWhere);

        /**查不到,orderId更改会引起路由查询失败*/
        OrderEntity predicate = new OrderEntity();
        predicate.setOrderId(10002L);
        OrderEntity entity = orderMapper.selectSingleByPredicate(predicate);
        log.info("after update orderEntity:"+JSON.toJSONString(entity));
    }

四、sharding建表

目前配置并验证了3个库,每库2个order表的场景:

如果分库分表数量比较多,仅仅创建表就是一件很繁琐的事情。sharding查询数据不指定分片规则字段时,会自动路由到各个库的各个表里查询,不知道大家有没有想到:如果配置要创建表的路由规则,用sharding来执行一条创建sql的语句,会不会就自动路由到各个库去执行了,也就代替人工去各个库建表了呢?下面来验证一下这个想法,以创建t_order_items表为例:

1、配置t_order_items的规则:

在上面配置t_order规则下面补充t_order_items的规则配置:

        // 省略配置order_item表规则...
        TableRuleConfiguration orderItemTableRuleConfig = new TableRuleConfiguration();
        orderItemTableRuleConfig.setLogicTable("t_order_items");
        orderItemTableRuleConfig.setActualDataNodes("db${0..2}.t_order_items_${0..1}");// 配置分库策略
        orderItemTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "db${order_id % 3}"));

        // 配置分表策略
        orderItemTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order_items_${order_id % 2}")); shardingRuleConfig.getTableRuleConfigs().add(orderItemTableRuleConfig);

2、t_order_items建表sql语句:

    <update id="createTItemsIfNotExistsTable">
        CREATE TABLE IF NOT EXISTS `t_order_items` (
          `id` bigint NOT NULL AUTO_INCREMENT,
          `order_id` bigint NOT NULL,
          `unique_no` varchar(32) NOT NULL,
          `quantity` int NOT NULL DEFAULT ‘1‘,
          `is_active` tinyint NOT NULL DEFAULT 1,
          `inserttime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
          `updatetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
          PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    </update>

3、OrderItemsMapper方法:

Integer createTItemsIfNotExistsTable();

4、执行方法:

orderItemsMapper.createTItemsIfNotExistsTable();

查看db0、db1、db2:

验证了我们上面的想法,建表成功了。

附录

如果没有配置t_order_items规则,执行建表sql会报错:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: io.shardingjdbc.core.exception.ShardingJdbcException: Cannot find table rule and default data source with logic table: ‘t_order_items‘
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: CREATE TABLE IF NOT EXISTS `t_order_items` ( `id` bigint NOT NULL AUTO_INCREMENT, `order_id` bigint NOT NULL, `unique_no` varchar(32) NOT NULL, `quantity` int NOT NULL DEFAULT ‘1‘, `is_active` tinyint NOT NULL DEFAULT 1, `inserttime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updatetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
### Cause: io.shardingjdbc.core.exception.ShardingJdbcException: Cannot find table rule and default data source with logic table: ‘t_order_items‘

原文地址:https://www.cnblogs.com/mr-yang-localhost/p/8280500.html

时间: 2024-08-03 07:25:03

【分库分表】sharding-jdbc实践—分库分表入门的相关文章

Sharding JDBC如何分库分表?看完你就会了

Sharding JDBC的操作分为配置使用.读写分离.分库分表以及应用等,今天我们主要来了解一下关于分库分表的操作,如果你对此感兴趣的话,那我们就开始吧. 环境准备 pom.xml <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE

一小时读懂Sharding JDBC之分库分表

作为轻量级java框架,sharding JDBC在Java的jdbc层提供了额外的服务,可以理解为增强版的jdbc驱动.其中,分库分表的操作是其中的重要一环,接下来就跟随我来看一看,这一操作如何进行. 环境准备 pom.xml <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <v

SpringBoot 整合 Sharding jdbc 实现应用层分库分表

1.官网链接参考: https://shardingsphere.apache.org/document/current/cn/quick-start/sharding-jdbc-quick-start/ 感谢 ShardingSphere 团队! 2.首先建立测试的数据库表: (1)表结构如下: (2)建表脚本如下: CREATE DATABASE `sharding0` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; USE `shar

转数据库分库分表(sharding)系列(二) 全局主键生成策略

本文将主要介绍一些常见的全局主键生成策略,然后重点介绍flickr使用的一种非常优秀的全局主键生成方案.关于分库分表(sharding)的拆分策略和实施细则,请参考该系列的前一篇文章:数据库分库分表(sharding)系列(一) 拆分实施策略和示例演示 本文原文连接: http://blog.csdn.net/bluishglc/article/details/7710738 ,转载请注明出处! 第一部分:一些常见的主键生成策略 一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键

数据库分库分表(sharding)系列

数据库分库分表(sharding)系列     目录; (一) 拆分实施策略和示例演示 (二) 全局主键生成策略 (三) 关于使用框架还是自主开发以及sharding实现层面的考量 (四) 多数据源的事务处理 (五) 一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案 (一) 拆分实施策略和示例演示 第一部分:实施策略 图1.数据库分库分表(sharding)实施策略图解 1.准备阶段 对数据库进行分库分表(Sharding化)前,需要开发人员充分了解系统业务逻辑和数据库sch

数据库分库分表(sharding)系列(二) 全局主键生成策略

本文将主要介绍一些常见的全局主键生成策略,然后重点介绍flickr使用的一种非常优秀的全局主键生成方案.关于分库分表(sharding)的拆分策略和实施细则,请参考该系列的前一篇文章:数据库分库分表(sharding)系列(一) 拆分实施策略和示例演示 本文原文连接: http://blog.csdn.net/bluishglc/article/details/7710738 ,转载请注明出处! 第一部分:一些常见的主键生成策略 一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键

数据库分库分表(sharding)系列(三) 关于使用框架还是自主开发以及sharding实现层面的考量

当团队对系统业务和数据库进行了细致的梳理,确定了切分方案后,接下来的问题就是如何去实现切分方案了,目前在sharding方面有不少的开源框架和产 品可供参考,同时很多团队也会选择自主开发实现,而不管是选择框架还是自主开发,都会面临一个在哪一层上实现sharding逻辑的问题,本文会对这一系 列的问题逐一进行分析和考量.本文原文连接: http://blog.csdn.net/bluishglc/article/details/7766508转载请注明出处! 一.sharding逻辑的实现层面 从

数据库分库分表(sharding)系列(一) 拆分实施策略和示例演示

本文原文连接: http://blog.csdn.net/bluishglc/article/details/7696085 ,转载请注明出处!本文着重介绍sharding切分策略,如果你对数据库sharding缺少基本的了解,请参考我另一篇从基础理论全面介绍sharding的文章:数据库Sharding的基本思想和切分策略 第一部分:实施策略 图1.数据库分库分表(sharding)实施策略图解(点击查看大图) 1.准备阶段 对数据库进行分库分表(Sharding化)前,需要开发人员充分了解系

数据库分库分表(sharding)

第一部分:实施策略 图1.数据库分库分表(sharding)实施策略图解(点击查看大图) 1.准备阶段 对数据库进行分库分表(Sharding化)前,需要开发人员充分了解系统业务逻辑和数据库schema.一个好的建议是绘制一张数据库ER图或领域模型图,以这类图为基础划分shard,直观易行,可以确保开发人员始终保持清醒思路.对于是选择数据库ER图还是领域模型图要根据项目自身情况进行选择.如果项目使用数据驱动的开发方式,团队以数据库ER图作为业务交流的基础,则自然会选择数据库ER图,如果项目使用的