Apache的shardingsphere分库分表+读写分离

1.引入maven依赖:

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>

2.准备数据库,我是搞了6个库,表结构都是一样的

>>> one_master,one_slave1,one_slave2

>>>  two_master,two_slave1,two_slave2

3.SQL脚本,每个库都要执行一份

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for dict
-- ----------------------------
DROP TABLE IF EXISTS `dict`;
CREATE TABLE `dict`  (
  `id` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键',
  `type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Table structure for user_0
-- ----------------------------
DROP TABLE IF EXISTS `user_0`;
CREATE TABLE `user_0`  (
  `phone` bigint(20) NOT NULL COMMENT '主键手机号',
  `user_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `pass_word` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
  `auth_code` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '验证码',
  `sex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别0:女,1:男,2未知;',
  `age` int(4) NULL DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`phone`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Table structure for user_1
-- ----------------------------
DROP TABLE IF EXISTS `user_1`;
CREATE TABLE `user_1`  (
  `phone` bigint(20) NOT NULL COMMENT '主键手机号',
  `user_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `pass_word` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
  `auth_code` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '验证码',
  `sex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别0:女,1:男,2未知;',
  `age` int(4) NULL DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`phone`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Table structure for user_2
-- ----------------------------
DROP TABLE IF EXISTS `user_2`;
CREATE TABLE `user_2`  (
  `phone` bigint(20) NOT NULL COMMENT '主键手机号',
  `user_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `pass_word` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
  `auth_code` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '验证码',
  `sex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别0:女,1:男,2未知;',
  `age` int(4) NULL DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`phone`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Table structure for user_info_0
-- ----------------------------
DROP TABLE IF EXISTS `user_info_0`;
CREATE TABLE `user_info_0`  (
  `id` int(64) NOT NULL COMMENT '主键id',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT 'user表的phone字段值',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Table structure for user_info_1
-- ----------------------------
DROP TABLE IF EXISTS `user_info_1`;
CREATE TABLE `user_info_1`  (
  `id` int(64) NOT NULL COMMENT '主键id',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT 'user表的phone字段值',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Table structure for user_info_2
-- ----------------------------
DROP TABLE IF EXISTS `user_info_2`;
CREATE TABLE `user_info_2`  (
  `id` int(64) NOT NULL COMMENT '主键id',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT 'user表的phone字段值',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

3.第一种:springboot的配置文件设置

spring:
  shardingsphere:
    datasource:
      names: ds-master1,ds-master1-slave1,ds-master1-slave2,ds-master2,ds-master2-slave1,ds-master2-slave2
      ############################################ <database1> ###################################################
      ####可以像我下面这么写ds-****,不可以这么写ds_****,会报错的
      ds-master1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/one_master?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
        username: root
        password: root
      ds-master1-slave1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/one_slave1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
        username: root
        password: root
      ds-master1-slave2:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/one_slave2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
        username: root
        password: root
      ############################################ <database2> ###################################################
      ds-master2:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/two_master?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
        username: root
        password: root
      ds-master2-slave1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/two_slave1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
        username: root
        password: root
      ds-master2-slave2:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/two_slave2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
        username: root
        password: root


    sharding:
      tables:
        ###### <user表> ######
        user:
          actual-data-nodes: ds$->{0..1}.user_$->{0..2}
          table-strategy:
            inline:
              sharding-column: phone
              algorithm-expression: user_$->{phone % 3}
        ###### <user_info表> ######
        user_info:
          actual-data-nodes: ds$->{0..1}.user_info_$->{0..2}
          table-strategy:
            inline:
              sharding-column: user_id
              algorithm-expression: user_info_$->{user_id % 3}
          key-generator:
            column: id
            type: SNOWFLAKE
      ####默认数据库策略
      default-database-strategy:
        inline:
          sharding-column: phone
          algorithm-expression: ds$->{phone % 2}

      ####绑定表>>>user表与user_info表有关系 例如:user的phone和user_info的user_id是一样的值
      binding-tables: user,user_info
      ####广播表>>>每个数据库都存在, 且数据都是一样的
      broadcast-tables: dict
      ####主从规则
      master-slave-rules:
        ds0:
          master-data-source-name: ds-master1
          slave-data-source-names: ds-master1-slave1,ds-master1-slave2
        ds1:
          master-data-source-name: ds-master2
          slave-data-source-names: ds-master2-slave1,ds-master2-slave2
    ####均衡方式
    masterslave:
      load-balance-algorithm-type: ROUND_ROBIN

  main:
    allow-bean-definition-overriding: true

4.第二种java代码

package com.example.common.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.example.common.db.apachesharding.ApacheShardingDatabase;
import com.example.common.db.apachesharding.ApacheShardingTable;
import com.google.common.collect.Lists;
import org.apache.shardingsphere.api.config.masterslave.MasterSlaveRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.KeyGeneratorConfiguration;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.core.constant.properties.ShardingPropertiesConstant;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;

/**
 * apache的分库分表
 * @author 孙灵达
 */
@Configuration
public class ApacheShardingConfig {


    /**
     * sharding
     * @author 孙灵达
     */
    @Bean
    public DataSource shardingDataSource() throws SQLException, ReflectiveOperationException {
        ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
        shardingRuleConfiguration.getTableRuleConfigs().add(getUserRuleConfig());
        shardingRuleConfiguration.getTableRuleConfigs().add(getUserInfoRuleConfig());
        shardingRuleConfiguration.getBindingTableGroups().add("user, user_info");
        shardingRuleConfiguration.getBroadcastTables().add("dict");
        shardingRuleConfiguration.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new ApacheShardingDatabase()));
        shardingRuleConfiguration.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new ApacheShardingTable()));
        shardingRuleConfiguration.setMasterSlaveRuleConfigs(getMasterSlaveConfig());

        Properties properties = new Properties();
        properties.setProperty(ShardingPropertiesConstant.SQL_SHOW.getKey(), "true");
        return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfiguration, properties);
    }


    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws SQLException, ReflectiveOperationException {
        DataSource dataSource = shardingDataSource();
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        return sessionFactoryBean;
    }

    @Bean
    public DataSourceTransactionManager transactionManager() throws SQLException, ReflectiveOperationException {
        DataSourceTransactionManager manager = new DataSourceTransactionManager();
        manager.setDataSource(shardingDataSource());
        return manager;
    }

    /**
     * user_info表的分片规则
     * @author 孙灵达
     */
    private TableRuleConfiguration getUserInfoRuleConfig() {
        TableRuleConfiguration userInfoRuleConfig = new TableRuleConfiguration("user_info", "ds${0..1}.user_info_${0..2}");
        KeyGeneratorConfiguration keyGeneratorConfiguration = new KeyGeneratorConfiguration("SNOWFLAKE", "id");
        userInfoRuleConfig.setKeyGeneratorConfig(keyGeneratorConfiguration);
        return userInfoRuleConfig;
    }

    /**
     * user表的分片规则
     * @author 孙灵达
     */
    private TableRuleConfiguration getUserRuleConfig() {
        TableRuleConfiguration userRuleConfig = new TableRuleConfiguration("user", "ds${0..1}.user_${0..2}");
        KeyGeneratorConfiguration keyGeneratorConfiguration = new KeyGeneratorConfiguration("SNOWFLAKE", "phone");
        userRuleConfig.setKeyGeneratorConfig(keyGeneratorConfiguration);
        return userRuleConfig;
    }

    /**
     * 获取主从数据源配置
     * @author 孙灵达
     */
    private List<MasterSlaveRuleConfiguration> getMasterSlaveConfig() {
        MasterSlaveRuleConfiguration msConfig1 =
                new MasterSlaveRuleConfiguration("ds0", "ds_master1", Arrays.asList("ds_master1_slave1", "ds_master1_slave2"));
        MasterSlaveRuleConfiguration msConfig2 =
                new MasterSlaveRuleConfiguration("ds1", "ds_master2", Arrays.asList("ds_master2_slave1", "ds_master2_slave2"));
        return Lists.newArrayList(msConfig1, msConfig2);
    }
    /**
     * 数据源配置
     * @author 孙灵达
     */
    private Map<String, DataSource> createDataSourceMap() throws ReflectiveOperationException {
        final Map<String, DataSource> dbMap = new HashMap<>();
        dbMap.put("ds_master1", getDataSource("one_master"));
        dbMap.put("ds_master1_slave1", getDataSource("one_slave1"));
        dbMap.put("ds_master1_slave2", getDataSource("one_slave2"));
        dbMap.put("ds_master2", getDataSource("two_master"));
        dbMap.put("ds_master2_slave1", getDataSource("two_slave1"));
        dbMap.put("ds_master2_slave2", getDataSource("two_slave2"));
        return dbMap;
    }

    /**
     * 获取数据源
     * @author 孙灵达
     */
    private DataSource getDataSource(final String dbName) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDbType("com.alibaba.druid.pool.DruidDataSource");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl(String.format("jdbc:mysql://127.0.0.1:3306/%s?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT", dbName));
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
}

 

5.我当时这么写的时候会报错

5.是因为默认加载了shardingsphere的SpringBootConfiguration, 然后排除掉, 就可以了

6.数据库分片策略, 要注意实现类PreciseShardingAlgorithm后面的类型, 要与你分片的实体类主键类型对应(可自己定义)

package com.example.common.db.apachesharding;

import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

import java.util.Collection;

public final class ApacheShardingDatabase implements PreciseShardingAlgorithm<Long> {
    @Override
    public String doSharding(final Collection<String> databaseNames, final PreciseShardingValue<Long> shardingValue) {
        for (String database : databaseNames) {
            if (database.endsWith((shardingValue.getValue() % 2) + "")) {
                System.out.println("数据库:" + database);
                return database;
            }
        }
        throw new UnsupportedOperationException();
    }
}

7.表的分片策略, 和分库策略一样, 类型要对应上

package com.example.common.db.apachesharding;

import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

import java.util.Collection;

public final class ApacheShardingTable implements PreciseShardingAlgorithm<Long> {
    @Override
    public String doSharding(final Collection<String> tableNames, final PreciseShardingValue<Long> shardingValue) {
        for (String table : tableNames) {
            if (table.endsWith(shardingValue.getValue() % 3 + "")) {
                System.out.println("表:" + table);
                return table;
            }
        }
        throw new UnsupportedOperationException();
    }
}

8.结果

>>>插入数据会根据分片的策略进行插入;

>>>selelct * from user也会查询出所有的数据:

>>>select * from user where phone = xx这样就不会查询到对应的库和表, 目前还没有解决, 如果有办法希望您留言解答

9.相关资料链接:

shardingsphere资料:

http://shardingsphere.apache.org/document/current/cn/quick-start/

https://blog.csdn.net/caohao1210/article/details/85108118

mysql主从复制:

https://blog.csdn.net/li_lening/article/details/81878163

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值