zoukankan      html  css  js  c++  java
  • Sharding-JDBC 快速入门(水平分表)

    介绍:

      Sharding-JDBC,定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

      Sharding-JDBC的核心功能为 数据分片 和 读写分离 ,通过 Sharding-JDBC,应用可以透明的使用 jdbc 访问已经分库分表、读写分离的多个数据源,而不用关心数据源的数量以及数据如何分布。

      适用于任何基于 Java 的ORM框架,如: Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。

      基于任何第三方的数据库连接池,如: DBCP, C3P0, BoneCP, Druid, HikariCP等。

      支持任意实现 JDBC 规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。

      使用Sharding-Jdbc前需要人工对数据库进行分库分表,在应用程序中加入Sharding-Jdbc的Jar包,应用程序通过Sharding-Jdbc操作分库分表后的数据库和数据表,由于Sharding-Jdbc是对Jdbc驱动的增强,使用Sharding-Jdbc就像使用Jdbc驱动一样,在应用程序中是无需指定具体要操作的分库和分表的。

    快速入门:

      1.需求说明

        人工创建两张表,t_order_1和t_order_2,这两张表是订单表拆分后的表,通过Sharding-Jdbc向订单表插入数据,按照一定的分片规则,主键为奇数的进入t_order_1,另一部分数据进入t_order_2,通过Sharding-Jdbc 查询数据,根据 SQL语句的内容从t_order_1或t_order_2查询数据。

      2.创建数据库,创建表

    CREATE DATABASE `order_db` CHARACTER SET 'utf8mb4';
    USE order_db;
    
    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 ;

      3.创建springboot工程,引入maven依赖

    <!-- sharding-jdbc和SpringBoot整合的Jar包 -->
    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
        <version>4.0.0-RC1</version>
    </dependency>

        具体spring boot相关依赖及配置省略.......

      4.分片规则配置

    #sharding-jdbc分片规则配置
    #数据源
    spring.shardingsphere.datasource.names = m1
    
    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:3306/order_db?useUnicode=true
    spring.shardingsphere.datasource.m1.username = root
    spring.shardingsphere.datasource.m1.password = root
    
    # 指定t_order表的数据分布情况,配置数据节点 m1.t_order_1,m1.t_order_2
    spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m1.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表的分片策略,分片策略包括分片键和分片算法  {order_id % 2 + 1}:计算出的值要么为1,要么为2,根据结果选择使用哪张表
    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

        1. 首先定义数据源m1,并对m1进行实际的参数配置。
        2.指定t_order表的数据分布情况,他分布在 m1.t_order_1,m1.t_order_2
        3.指定t_order表的主键生成策略为SNOWFLAKE,SNOWFLAKE是一种分布式自增算法,保证id全局唯一
        4.定义t_order分片策略,order_id为偶数的数据落在t_order_1,为奇数的落在t_order_2,分表策略的表达式为 t_order_$->{order_id % 2 + 1}

      5.持久层

    @Mapper
    public interface OrderDao {
    
        /**
         * 插入订单
         * @param price
         * @param userId
         * @param status
         * @return
         */
        @Insert("insert into t_order(price, user_id, status) values(#{price}, #{userId}, #{status})")
        int insertOrder(BigDecimal price, Long userId, String status);
    
        /**
         * 根据id列表查询订单
         * @param orderIds
         * @return
         */
        @Select("<script>" +
                "select" +
                " * " +
                " from t_order o " +
                " where o.order_id in " +
                " <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" +
                " #{id} " +
                " </foreach>" +
                "</script>")
        List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds);
    }

      6.测试

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = {ShardingJdbcSimpleBootstrap.class})
    public class OrderDaoTest {
    
        @Autowired
        OrderDao orderDao;
    
        @Test
        public void testInsertOrder() {
            // for (int i = 1; i <= 20; i++) {
                orderDao.insertOrder(new BigDecimal(21), 1L, "SUCCESS");
            // }
        }
    
        @Test
        public void testSelectOrderbyIds() {
            List<Long> ids = new ArrayList<>();
            ids.add(463369285373263872L);
            ids.add(463369285301960704L);
    
            List<Map> maps = orderDao.selectOrderbyIds(ids);
            System.out.println(maps);
        }
    }

    执行流程:

      查看日志,Sharding-JDBC在拿到用户要执行的sql之后干了哪些事儿:
        (1)解析sql,获取片键值,在本例中是order_id
        (2)Sharding-JDBC通过规则配置 t_order_$->{order_id % 2 + 1},知道了当order_id为偶数时,应该往t_order_1表插数据,为奇数时,往t_order_2插数据。
        (3)于是Sharding-JDBC根据order_id的值改写sql语句,改写后的SQL语句是真实所要执行的SQL语句。
        (4)执行改写后的真实sql语句
        (5)将所有真正执行sql的结果进行汇总合并,返回。

    Java配置类的方式配置分片规则:

    @Configuration
    public class ShardingJdbcConfig {
    
        // 配置分片规则
        // 定义数据源
        Map<String, DataSource> createDataSourceMap() {
            DruidDataSource dataSource1 = new DruidDataSource();
            dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource1.setUrl("jdbc:mysql://localhost:3306/order_db?useUnicode=true");
            dataSource1.setUsername("root");
            dataSource1.setPassword("root");
            Map<String, DataSource> result = new HashMap<>();
            result.put("m1", dataSource1);
            return result;
        }
    
        // 定义主键生成策略
        private static KeyGeneratorConfiguration getKeyGeneratorConfiguration() {
            KeyGeneratorConfiguration result = new KeyGeneratorConfiguration("SNOWFLAKE", "order_id");
            return result;
        }
    
        // 定义t_order表的分片策略
        TableRuleConfiguration getOrderTableRuleConfiguration() {
            TableRuleConfiguration result = new TableRuleConfiguration("t_order", "m1.t_order_$->{1..2}");
            result.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order_$->{order_id % 2 + 1}"));
            result.setKeyGeneratorConfig(getKeyGeneratorConfiguration());
    
            return result;
        }
    
        // 定义sharding-Jdbc数据源
        @Bean
        DataSource getShardingDataSource() throws SQLException {
            ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
            shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
            //spring.shardingsphere.props.sql.show = true
            Properties properties = new Properties();
            properties.put("sql.show", "true");
            return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, properties);
        }
    }

      由于采用了配置类所以需要屏蔽原来 application.properties 文件中spring.shardingsphere开头的配置信息。
      需要在SpringBoot启动类中屏蔽使用spring.shardingsphere配置项的类:@SpringBootApplication(exclude = SpringBootConfiguration.class)

  • 相关阅读:
    月亮,还是馅饼(2)
    月亮,还是馅饼(1)
    spread 论坛
    kaok website
    提升 .NET 程序性能的 一些 原则
    sql convert
    sql 中 MSDTC 不可用。
    判断sql执行所花的时间(精度为毫秒)
    35岁以前成功的12条黄金法则
    快速删除表中的数据
  • 原文地址:https://www.cnblogs.com/roadlandscape/p/12818732.html
Copyright © 2011-2022 走看看