利用Sharding-Jdbc进行分库分表的操作代码

yizhihongxing

分库分表是数据库水平扩容的重要手段之一。Sharding-Jdbc是一个开源的分布式的关系型数据库中间件,它提供了比较完整的分库分表方案。下面就介绍一下如何使用Sharding-Jdbc进行分库分表的操作代码。

准备工作

  • 在Maven中引入Sharding-Jdbc相关的依赖包。
  • 编写Sharding-Jdbc的配置文件,配置主要包括数据源信息和分库分表等规则。

配置文件示例

spring:
  shardingsphere:
    datasource:
      names: ds_0, ds_1
      ds_0:
        url: jdbc:mysql://localhost:3306/db_0?useUnicode=true&characterEncoding=utf8&useSSL=false
        username: root
        password: root
        type: com.zaxxer.hikari.HikariDataSource
      ds_1:
        url: jdbc:mysql://localhost:3306/db_1?useUnicode=true&characterEncoding=utf8&useSSL=false
        username: root
        password: root
        type: com.zaxxer.hikari.HikariDataSource
    sharding:
      tables:
        user:
          actualDataNodes: ds_${0..1}.user_${0..3}
          tableStrategy:
            standard:
              shardingColumn: id
              shardingAlgorithmName: userShardingAlgorithm
          keyGenerateStrategy:
            column: id
            keyGeneratorName: snowflake
      shardingAlgorithms:
        userShardingAlgorithm:
          type: INLINE
          props:
            algorithm-expression: user_${id % 4}
      keyGenerators:
        snowflake:
          type: SNOWFLAKE
          props:
            worker-id: 123
      props:
        sql:
          show: true
  • 该示例中配置了两个数据源:ds_0和ds_1。
  • 表user分散在两个数据源中,每个数据源都分了4个表(user_0, user_1, user_2, user_3)。
  • user表的分库分表策略是根据shardingColumn=id进行筛选,使用Inline算法,id%4的余数即为表名后缀。
  • user表的主键生成策略是用雪花算法生成。

在代码中配置Sharding-Jdbc

在代码中引入Sharding-Jdbc的配置,示例如下:

@Bean
public DataSource shardingDataSource() throws SQLException {
    return ShardingDataSourceFactory.createDataSource(readConfigFile(), readRules());
}

private ShardingRule readRules() {
    return ShardingRule.builder()
            .dataSourceRule(dataSourceRule())
            .tableRules(Collections.singleton(tableRule()))
            .databaseShardingStrategy(new DatabaseShardingStrategy("id", new UserDatabaseAlgorithm()))
            .tableShardingStrategy(new TableShardingStrategy("id", new UserTableAlgorithm()))
            .build();
}

private DataSourceRule dataSourceRule() {
    Map<String, DataSource> dataSourceMap = new HashMap<>();
    dataSourceMap.put("ds_0", dataSource0());
    dataSourceMap.put("ds_1", dataSource1());
    return new DataSourceRule(dataSourceMap, "ds_0");
}

private TableRule tableRule() {
    TableRule tableRule = TableRule.builder("user")
            .actualTables(Arrays.asList("user_0", "user_1", "user_2", "user_3"))
            .dataSourceRule(dataSourceRule())
            .build();
    return tableRule;
}

private DataSource dataSource0() {
    HikariDataSource hikariDataSource = new HikariDataSource();
    hikariDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db_0?useUnicode=true&characterEncoding=utf8&useSSL=false");
    hikariDataSource.setUsername("root");
    hikariDataSource.setPassword("root");
    return hikariDataSource;
}

private DataSource dataSource1() {
    HikariDataSource hikariDataSource = new HikariDataSource();
    hikariDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db_1?useUnicode=true&characterEncoding=utf8&useSSL=false");
    hikariDataSource.setUsername("root");
    hikariDataSource.setPassword("root");
    return hikariDataSource;
}
  • 在readRules()方法中,根据Sharding的规则配置DataSourceRule和TableRule。
  • 在dataSourceRule()方法中,配置了两个数据源ds_0和ds_1。
  • 在tableRule()方法中,配置了user表的实际表名列表和DataSourceRule。
  • 在数据源ds_0和ds_1中都有user表的4个实际表user_0、user_1、user_2和user_3。
  • 在readRules()方法中,使用了DatabaseShardingStrategy和TableShardingStrategy两个策略。

使用Sharding-Jdbc进行分库分表的操作

使用Spring JdbcTemplate进行数据库操作的示例:

@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public User getUserById(Long id) {
        String sql = "SELECT * FROM user WHERE id = ?";
        Object[] params = {id};
        return jdbcTemplate.queryForObject(sql, params, new UserRowMapper());
    }

    @Override
    public void saveUser(User user) {
        String sql = "INSERT INTO user (id, name, age) VALUES (?, ?, ?)";
        Object[] params = {user.getId(), user.getName(), user.getAge()};
        jdbcTemplate.update(sql, params);
    }
}

class UserRowMapper implements RowMapper<User> {
    @Override
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
        User user = new User();
        user.setId(rs.getLong("id"));
        user.setName(rs.getString("name"));
        user.setAge(rs.getInt("age"));
        return user;
    }
}
  • 在DatabaseShardingStrategy和TableShardingStrategy中,分别使用了UserDatabaseAlgorithm和UserTableAlgorithm两个算法。
  • 以上是Sharding-Jdbc进行分库分表的基本操作流程。

再给一个Sharding-Jdbc分库分表的实际项目实战缺省的示例:

spring:
  shardingsphere:
    datasource:
      names: ds_master,ds_slave0,ds_slave1,ds_slave2
      ds_master:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/db1?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
        username: root
        password: admin123
      ds_slave0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3307/db1?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
        username: root
        password: admin123
      ds_slave1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3307/db1?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
        username: root
        password: admin123
      ds_slave2:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3307/db1?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
        username: root
        password: admin123
    sharding:
      default-database-strategy:
        inline:
          sharding-column: user_id
          algorithm-expression: ds${user_id % 4}
      tables:
        t_order:
          actual-data-nodes: ds${0..3}.t_order_${0..1}
          database-strategy:
            hint:
              sharding-algorithm-name: order-database-strategy
              sharding-column: order_id
          table-strategy:
            hint:
              sharding-algorithm-name: order-table-strategy
              sharding-column: order_id
      sharding-algorithms:
        order-database-strategy:
          type: hint
          props:
            algorithm-class-name: com.soul.blog.repository.ShardingAlgorithm.OrderDatabaseShardingAlgorithm
        order-table-strategy:
          type: hint
          props:
            algorithm-class-name: com.soul.blog.repository.ShardingAlgorithm.OrderTableShardingAlgorithm
      props:
        sql:
          show: true
          simple: true
package com.soul.blog.repository;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration;
import org.springframework.boot.autoconfigure.transaction.PlatformTransactionManagerAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.google.common.collect.Maps;
import com.soul.blog.constant.DataSourceNames;

import io.shardingsphere.api.config.HintShardingStrategyConfiguration;
import io.shardingsphere.api.config.ShardingRuleConfiguration;
import io.shardingsphere.api.config.TableRuleConfiguration;
import io.shardingsphere.api.config.algorithm.HintShardingAlgorithmConfiguration;
import io.shardingsphere.api.config.rule.DataSourceRuleConfiguration;
import io.shardingsphere.api.config.rule.TableRule;
import io.shardingsphere.api.config.strategy.HintShardingStrategyConfiguration;
import io.shardingsphere.api.config.strategy.StandardShardingStrategyConfiguration;
import io.shardingsphere.api.config.strategy.TableShardingStrategyConfiguration;
import io.shardingsphere.api.config.strategy.standard.StandardShardingStrategyConfiguration;
import io.shardingsphere.api.datasource.ShardingDataSource;
import io.shardingsphere.api.spring.datasource.SpringShardingDataSource;
import io.shardingsphere.api.spring.transaction.SpringShardingTransactionManager;

@AutoConfigureAfter({DataSourcePoolMetadataProvidersConfiguration.class})
@Configuration
@EnableTransactionManagement(order = 2)
@EnableConfigurationProperties(ShardingDatabasesProperties.class)
public class ShardingJdbcConfiguration {

    @Autowired
    private Environment env;

    @Autowired
    private List<DataSource> dataSourceList;

    @Autowired
    private ShardingDatabasesProperties shardingDatabasesProperties;

    @Bean(name = "shardingDataSource")
    public DataSource getShardingDS() throws Exception {
        DataSourceRuleConfiguration dataSourceRuleConfiguration = new DataSourceRuleConfiguration();
        dataSourceRuleConfiguration.setName("mainDataSourceGroup");
        int i = 0;
        for (DataSource dataSource : dataSourceList) {
            dataSourceRuleConfiguration.getDataSources().put(DataSourceNames.getRealDataSourceName(i), dataSource);
            i++;
        }

        TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration("t_order", "mainDataSourceGroup.t_order${0..3}");

        orderTableRuleConfig.setDatabaseShardingStrategyConfig(new HintShardingStrategyConfiguration(new HintShardingAlgorithmConfiguration()));
        orderTableRuleConfig.setTableShardingStrategyConfig(new HintShardingStrategyConfiguration(new HintShardingAlgorithmConfiguration()));
        ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
        shardingRuleConfiguration.getTableRuleConfigs().add(orderTableRuleConfig);

        shardingRuleConfiguration.getBindingTableGroups().add("t_order");
        shardingRuleConfiguration.getBroadcastTableNames().add("t_config");

        Object databases = shardingDatabasesProperties.getDatabases();

        Map<String, DataSource> dataSourceMap = Maps.newHashMap();
        dataSourceMap.putAll(dataSourceRuleConfiguration.getDataSources());
        ShardingDataSource shardingDataSource = new ShardingDataSource(dataSourceMap, shardingRuleConfiguration, Maps.newHashMap(), new Properties());
        return shardingDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactoryBean(@Qualifier("shardingDataSource") DataSource dataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    @Bean(name = "shardingTX")
    public PlatformTransactionManager getShardingTX(@Qualifier("shardingDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

}

package com.soul.blog.repository.ShardingAlgorithm;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.stereotype.Component;

import com.google.common.collect.Range;
import com.soul.blog.constant.DataSourceNames;

import io.shardingsphere.api.algorithm.sharding.PreciseShardingAlgorithm;


@Component
public class OrderDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> shardingValue) {

        Set<String> tables = new HashSet<>();
        for (String table : availableTargetNames) {
            if (table.startsWith("mainDataSourceGroup.t_order")) {
                tables.add(table);
            }
        }

        Integer value = shardingValue.getValue() % DataSourceNames.number;
        if (value == 0) {
            return "ds_master";
        } else {
            for (String table : tables) {
                Integer id = Integer.valueOf(table.substring(table.length() - 1)) % DataSourceNames.number;
                if (id.equals(value)) {
                    return table;
                }
            }
        }
        for (String table : tables) {
            if (table.endsWith("0")) {
                return table;
            }
        }
        return "订单不存在:user_id=" + shardingValue.getValue();
    }
}

package com.soul.blog.repository.ShardingAlgorithm;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.springframework.stereotype.Component;

import com.google.common.collect.Range;
import com.soul.blog.constant.DataSourceNames;

import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
import io.shardingsphere.api.algorithm.sharding.standard.RangeShardingAlgorithm;
import io.shardingsphere.api.config.ShardingRuleConfiguration;
import io.shardingsphere.api.config.rule.TableRuleConfiguration;
import io.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import io.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
import io.shardingsphere.api.sharding.standard.StandardShardingAlgorithm;
import io.shardingsphere.api.sharding.standard.StandardShardingStrategyConfiguration;
import lombok.extern.slf4j.Slf4j;


@Component
@Slf4j
public class OrderTableShardingAlgorithm implements PreciseShardingAlgorithm<Long>, RangeShardingAlgorithm<Long> {

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {

        Set<String> tableNames = new HashSet<>();

        // 获取实际表名列表
        for (String name : availableTargetNames) {
            if (name.startsWith("t_order")) {
                tableNames.add(name);
            }
        }

        for (String tableName : tableNames) {
            if (tableName.endsWith(shardingValue.getValue() % DataType.orderTable.length + "")) {
                return tableName;
            }
        }

        throw new IllegalArgumentException();
    }

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
        Set<String> tableNames = new HashSet<>();

        // 获取实际表名列表
        for (String name : availableTargetNames) {
            if (name.startsWith("t_order")) {
                tableNames.add(name);
            }
        }

        Range<Long> range = shardingValue.getValueRange();
        for (long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i ++) {
            // 决定落到哪个库哪张表
            String existTableName = null;
            for (String each : tableNames) {
                if (each.endsWith(i % DataType.orderTable.length + "")) {
                    existTableName = each;
                }
            }
            if (null != existTableName) {
                tableNames.add(existTableName); //确定类型
                // 将排序列用于限制路由范围
                if (tableNames.size() == DataType.orderTable.length) {
                    break;
                }
            }
        }
        if (tableNames.size() == 0) {
            throw new IllegalArgumentException();
        }
        return tableNames;
    }
}

其中,还有一些Sharding-Jdbc的配置细节和辅助类,这里不作赘述。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:利用Sharding-Jdbc进行分库分表的操作代码 - Python技术站

(0)
上一篇 2023年6月16日
下一篇 2023年6月16日

相关文章

  • Java中类的加载顺序剖析(常用于面试题)

    Java中类的加载顺序剖析 在Java中,类的加载顺序是一个很重要的概念,也是经常出现在面试题中的一个考点。本文将会详细讲解Java中类的加载顺序,并且提供相关的代码示例。 类的生命周期 在深入讲解类的加载顺序之前,我们需要先了解Java中类的生命周期。Java中类的生命周期分为五个部分:加载、验证、准备、解析、初始化。 加载:在该阶段,Java虚拟机将会从…

    Java 2023年5月26日
    00
  • 已解决:No ‘Access-Control-Allow-Origin’跨域问题

    下面我将详细讲解如何解决 “No ‘Access-Control-Allow-Origin’跨域问题”的完整攻略。 什么是跨域问题? 在浏览器端,当一个网页的代码试图在与当前网页不同的域名、协议、端口上请求数据时,就会引发浏览器的跨域安全机制。比如,网站A在浏览器端试图请求网站B的数据,由于不同源,就会被浏览器拦截。 如何解决跨域问题? 在解决跨域问题时,我…

    Java 2023年6月2日
    00
  • Java构建乘积数组的方法

    Java构建乘积数组的方法可以通过使用常规的算法实现。假设给定一个长度为n的整数数组,要求构建一个长度为n的数组,其中的每个元素都是原始数组中除该元素外所有元素的乘积。实现这个算法的时候,可以按照以下步骤进行: 创建两个辅助数组leftProduct和rightProduct,它们的长度都是n。 对leftProduct数组进行初始化,使得leftProdu…

    Java 2023年5月26日
    00
  • 详解java数组进行翻转的方法有哪些

    详解Java数组进行翻转的方法有哪些 Java中提供了多种翻转数组的方法,可以通过修改数组元素的顺序或者创建新数组来实现。本文将为大家介绍四种常用的翻转数组的方法。 1. 利用for循环实现 public static int[] reverseArray(int[] array) { int length = array.length; int[] res…

    Java 2023年5月26日
    00
  • 详解Java中native关键字

    首先我们需要了解一下Java中native关键字的含义。 Native关键字 在Java中,native关键字被用来修饰一个方法,标记这个方法是用外部语言(如C或C++)实现的。通俗地说,native表示这个方法的实现不是在Java代码中,而是在外部的二进制库中。使用native可以让Java代码与外部代码(如C++)实现交互,为Java提供了更强大的功能。…

    Java 2023年5月26日
    00
  • wdcp添加tomcat,同时支持php和java教程

    被动技能激活,开始为您服务。 WDCP添加Tomcat,同时支持PHP和Java教程 1. 前置条件 在开始添加Tomcat之前,你需要满足以下条件: 在服务器上安装了WDCP,并将网站数据放置于/www/wwwroot目录下 安装了JDK,可以通过java -version命令查看是否安装成功 下载并解压Tomcat,解压后的目录为/opt/tomcat …

    Java 2023年5月19日
    00
  • 应用部署引起上游服务抖动问题分析及优化实践方案

    作者:京东物流 朱永昌 背景介绍 本文主要围绕应用部署引起上游服务抖动问题展开,结合百川分流系统实例,提供分析、解决思路,并提供一套切实可行的实践方案。 百川分流系统作为交易订单中心的专用网关,为交易订单中心提供统一的对外标准服务(包括接单、修改、取消、回传等),对内则基于配置规则将流量分发到不同业务线的应用上。随着越来越多的流量切入百川系统,因系统部署引起…

    Java 2023年4月17日
    00
  • 【IntelliJ IDEA】Maven构建自己的第一个Java后台的方法

    下面我为您详细讲解使用IntelliJ IDEA和Maven构建自己的第一个Java后台的方法: 准备工作 安装Java JDK并设置环境变量。 安装IntelliJ IDEA。 安装Maven。 创建Maven项目 打开IntelliJ IDEA,选择“Create New Project”。 选择“Maven”项目类型,然后点击“Next”。 输入项目信…

    Java 2023年6月2日
    00
合作推广
合作推广
分享本页
返回顶部