iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >springboot怎么配置sharding-jdbc水平分表
  • 855
分享到

springboot怎么配置sharding-jdbc水平分表

2023-06-21 21:06:09 855人浏览 独家记忆
摘要

这篇文章主要讲解了“SpringBoot怎么配置sharding-jdbc水平分表”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“springboot怎么配置sharding-jdbc水平分表

这篇文章主要讲解了“SpringBoot怎么配置sharding-jdbc水平分表”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“springboot怎么配置sharding-jdbc水平分表”吧!

关于依赖

shardingsphere-jdbc-core-spring-boot-starter

官方给出了Spring Boot Starter配置

<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> <version>${shardingsphere.version}</version></dependency>

但是基于已有项目,添加shardingsphere自动配置是很恶心的事

为什么配置了某个数据连接池的spring-boot-starter(比如druid)和 shardingsphere-jdbc-spring-boot-starter 时,系统启动会报错?

回答:

因为数据连接池的starter(比如druid)可能会先加载并且其创建一个默认数据源,这将会使得 ShardingSphere‐JDBC 创建数据源时发生冲突。

解决办法为,去掉数据连接池的starter 即可,sharing‐jdbc 自己会创建数据连接池。

一般项目已经有自己的DataSource了,如果使用shardingsphere-jdbc的自动配置,就必须舍弃原有的DataSource。

shardingsphere-jdbc-core

为了不放弃原有的DataSource配置,我们只引入shardingsphere-jdbc-core依赖

<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>4.1.1</version></dependency>

如果只水平分表,只支持mysql,可以排除一些无用的依赖

<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>4.1.1</version> <exclusions>  <exclusion>   <groupId>org.apache.shardingsphere</groupId>   <artifactId>shardingsphere-sql-parser-postgresql</artifactId>        </exclusion>        <exclusion>         <groupId>org.apache.shardingsphere</groupId>         <artifactId>shardingsphere-sql-parser-oracle</artifactId>        </exclusion>        <exclusion>         <groupId>org.apache.shardingsphere</groupId>         <artifactId>shardingsphere-sql-parser-sqlserver</artifactId>        </exclusion>        <exclusion>         <groupId>org.apache.shardingsphere</groupId>         <artifactId>encrypt-core-rewrite</artifactId>        </exclusion>        <exclusion>         <groupId>org.apache.shardingsphere</groupId>         <artifactId>shadow-core-rewrite</artifactId>        </exclusion>        <exclusion>         <groupId>org.apache.shardingsphere</groupId>         <artifactId>encrypt-core-merge</artifactId>        </exclusion>        <exclusion>         <!-- 数据库连接池,一般原有项目已引入其他的连接池 -->         <groupId>com.zaxxer</groupId>         <artifactId>HikariCP</artifactId>        </exclusion>        <exclusion>         <!-- 也是数据库连接池,一般原有项目已引入其他的连接池 -->         <groupId>org.apache.commons</groupId>         <artifactId>commons-dbcp2</artifactId>        </exclusion>        <exclusion>         <!-- 对象池,可以不排除 -->         <groupId>commons-pool</groupId>         <artifactId>commons-pool</artifactId>        </exclusion>        <exclusion>         <groupId>com.h3Database</groupId>         <artifactId>h3</artifactId>        </exclusion>        <exclusion>         <!-- Mysql驱动,原项目已引入,为了避免改变原有版本号,排除了吧 -->         <groupId>mysql</groupId>         <artifactId>mysql-connector-java</artifactId>        </exclusion>        <exclusion>         <groupId>org.postgresql</groupId>         <artifactId>postgresql</artifactId>        </exclusion>        <exclusion>         <groupId>com.microsoft.sqlserver</groupId>         <artifactId>mssql-jdbc</artifactId>        </exclusion> </exclusions></dependency>

数据源DataSource

原DataSource

以Druid为例,原配置为

package com.xxx.common.autoConfiguration;import java.util.ArrayList;import java.util.List;import javax.sql.DataSource;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.WEB.servlet.FilterReGIStrationBean;import org.springframework.boot.web.servlet.ServletRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import com.alibaba.druid.filter.Filter;import com.alibaba.druid.filter.logging.Slf4jLogFilter;import com.alibaba.druid.filter.stat.StatFilter;import com.alibaba.druid.pool.DruidDataSource;import com.alibaba.druid.support.Http.StatViewServlet;import com.alibaba.druid.support.http.WebStatFilter;import com.alibaba.druid.wall.WallConfig;import com.alibaba.druid.wall.WallFilter;import lombok.extern.slf4j.Slf4j;@Configuration@Slf4jpublic class DruidConfiguration { @Value("${spring.datasource.driver-class-name}")  private String driver;  @Value("${spring.datasource.url}") private String url;  @Value("${spring.datasource.username}")  private String username;  @Value("${spring.datasource.passWord}")  private String password; @Value("${datasource.druid.initialsize}") private Integer druid_initialsize = 0;  @Value("${datasource.druid.maxactive}") private Integer druid_maxactive = 20;  @Value("${datasource.druid.minidle}") private Integer druid_minidle = 0;  @Value("${datasource.druid.maxwait}") private Integer druid_maxwait = 30000; @Bean    public ServletRegistrationBean druidServlet() {     ServletRegistrationBean reg = new ServletRegistrationBean();     reg.setServlet(new StatViewServlet());        reg.addUrlMappings("/druid    @Bean    public DataSource druidDataSource() {     // 数据源        DruidDataSource druidDataSource = new DruidDataSource();        druidDataSource.setDriverClassName(driver); // 驱动        druidDataSource.setUrl(url); // 数据库连接地址        druidDataSource.setUsername(username); // 数据库用户名        druidDataSource.setPassword(password); // 数据库密码                druidDataSource.setInitialSize(druid_initialsize);// 初始化连接大小        druidDataSource.setMaxActive(druid_maxactive); // 连接池最大使用连接数量        druidDataSource.setMinIdle(druid_minidle); // 连接池最小空闲        druidDataSource.setMaxWait(druid_maxwait); // 获取连接最大等待时间                // 打开PSCache,并且指定每个连接上PSCache的大小        druidDataSource.setPoolPreparedStatements(false);         druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(33);                //druidDataSource.setValidationQuery("SELECT 1"); // 用来检测连接是否有效的sql        druidDataSource.setTestOnBorrow(false); // 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。        druidDataSource.setTestOnReturn(false); // 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能        druidDataSource.setTestWhileIdle(false); // 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效                druidDataSource.setTimeBetweenLogStatsMillis(60000); // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒        druidDataSource.setMinEvictableIdleTimeMillis(1800000); // 配置一个连接在池中最小生存的时间,单位是毫秒        // 当程序存在缺陷时,申请的连接忘记关闭,这时候,就存在连接泄漏        // 配置removeAbandoned对性能会有一些影响,建议怀疑存在泄漏之后再打开。在上面的配置中,如果连接超过30分钟未关闭,就会被强行回收,并且日志记录连接申请时的调用堆栈。        druidDataSource.setRemoveAbandoned(false); // 打开removeAbandoned功能         druidDataSource.setRemoveAbandonedTimeout(1800); // 1800秒,也就是30分钟        druidDataSource.setLogAbandoned(false); // 关闭abanded连接时输出错误日志                // 过滤器        List<Filter> filters = new ArrayList<Filter>();        filters.add(this.getStatFilter()); // 监控        //filters.add(this.getSlf4jLogFilter()); // 日志        filters.add(this.getWallFilter()); // 防火墙        druidDataSource.setProxyFilters(filters);        log.info("连接池配置信息:"+druidDataSource.getUrl());        return druidDataSource;    } @Bean    public FilterRegistrationBean filterRegistrationBean() {        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();        WebStatFilter webStatFilter = new WebStatFilter();        filterRegistrationBean.setFilter(webStatFilter);        filterRegistrationBean.addUrlPatterns("    public StatFilter getStatFilter(){     StatFilter sFilter = new StatFilter();     //sFilter.setSlowSqlMillis(2000); // 慢sql,毫秒时间      sFilter.setLogSlowSql(false); // 慢sql日志     sFilter.setMergeSql(true); // sql合并优化处理     return sFilter;    }            public Slf4jLogFilter getSlf4jLogFilter(){     Slf4jLogFilter slFilter =  new Slf4jLogFilter();     slFilter.setResultSetLogEnabled(false);      slFilter.setStatementExecutableSqlLogEnable(false);     return slFilter;    }        public WallFilter getWallFilter(){     WallFilter wFilter = new WallFilter();     wFilter.setDbType("mysql");     wFilter.setConfig(this.getWallConfig());     wFilter.setLogViolation(true); // 对被认为是攻击的SQL进行LOG.error输出     wFilter.setThrowException(true); // 对被认为是攻击的SQL抛出SQLExcepton     return wFilter;    }        public WallConfig getWallConfig(){     WallConfig wConfig = new WallConfig();     wConfig.setDir("META-INF/druid/wall/mysql"); // 指定配置装载的目录     // 拦截配置-语句      wConfig.setTruncateAllow(false); // truncate语句是危险,缺省打开,若需要自行关闭     wConfig.setCreateTableAllow(true); // 是否允许创建表     wConfig.setAlterTableAllow(false); // 是否允许执行Alter Table语句     wConfig.setDropTableAllow(false); // 是否允许修改表     // 其他拦截配置     wConfig.setStrictSyntaxCheck(true); // 是否进行严格的语法检测,Druid SQL Parser在某些场景不能覆盖所有的SQL语法,出现解析SQL出错,可以临时把这个选项设置为false,同时把SQL反馈给Druid的开发者     wConfig.setConditionOpBitwseAllow(true); // 查询条件中是否允许有"&"、"~"、"|"、"^"运算符。     wConfig.setMinusAllow(true); // 是否允许SELECT * FROM A MINUS SELECT * FROM B这样的语句     wConfig.setIntersectAllow(true); // 是否允许SELECT * FROM A INTERSECT SELECT * FROM B这样的语句     //wConfig.setMetadataAllow(false); // 是否允许调用Connection.getMetadata方法,这个方法调用会暴露数据库的表信息     return wConfig;    }}

可见,如果用自动配置的方式放弃这些原有的配置风险有多大

怎么改呢?

ShardingJdbcDataSource

第一步,创建一个interface,用以加载自定义的分表策略

可以在各个子项目中创建bean,实现此接口

public interface ShardingRuleSupport { void configRule(ShardingRuleConfiguration shardingRuleConfig);}

第二步,在DruidConfiguration.class中注入所有的ShardingRuleSupport

@Autowired(required = false)private List<ShardingRuleSupport> shardingRuleSupport;

第三步,创建sharding-jdbc分表数据源

//包装Druid数据源Map<String, DataSource> dataSourceMap = new HashMap<>();//自定义一个名称为ds0的数据源名称,包装原有的Druid数据源,还可以再定义多个数据源//因为只分表不分库,所有定义一个数据源就够了dataSourceMap.put("ds0", druidDataSource);//加载分表配置ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();//要加载所有的ShardingRuleSupport实现bean,所以用for循环加载for (ShardingRuleSupport support : shardingRuleSupport) { support.configRule(shardingRuleConfig);}//加载其他配置Properties properties = new Properties();//由于未使用starter的自动装配,所以手动设置,是否显示分表sqlproperties.put("sql.show", sqlShow);//返回ShardingDataSource包装的数据源return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, properties);

完整的ShardingJdbcDataSource配置

package com.xxx.common.autoConfiguration;import java.util.ArrayList;import java.util.List;import javax.sql.DataSource;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.boot.web.servlet.ServletRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import com.alibaba.druid.filter.Filter;import com.alibaba.druid.filter.logging.Slf4jLogFilter;import com.alibaba.druid.filter.stat.StatFilter;import com.alibaba.druid.pool.DruidDataSource;import com.alibaba.druid.support.http.StatViewServlet;import com.alibaba.druid.support.http.WebStatFilter;import com.alibaba.druid.wall.WallConfig;import com.alibaba.druid.wall.WallFilter;import lombok.extern.slf4j.Slf4j;@Configuration@Slf4jpublic class DruidConfiguration { @Value("${spring.datasource.driver-class-name}")  private String driver;  @Value("${spring.datasource.url}") private String url;  @Value("${spring.datasource.username}")  private String username;  @Value("${spring.datasource.password}")  private String password; @Value("${datasource.druid.initialsize}") private Integer druid_initialsize = 0;  @Value("${datasource.druid.maxactive}") private Integer druid_maxactive = 20;  @Value("${datasource.druid.minidle}") private Integer druid_minidle = 0;  @Value("${datasource.druid.maxwait}") private Integer druid_maxwait = 30000;  @Value("${spring.shardingsphere.props.sql.show:false}") private boolean sqlShow; @Autowired(required = false) private List<ShardingRuleSupport> shardingRuleSupport; @Bean    public ServletRegistrationBean druidServlet() {     ServletRegistrationBean reg = new ServletRegistrationBean();     reg.setServlet(new StatViewServlet());        reg.addUrlMappings("/druid    @Bean    public DataSource druidDataSource() {     // 数据源        DruidDataSource druidDataSource = new DruidDataSource();        druidDataSource.setDriverClassName(driver); // 驱动        druidDataSource.setUrl(url); // 数据库连接地址        druidDataSource.setUsername(username); // 数据库用户名        druidDataSource.setPassword(password); // 数据库密码                druidDataSource.setInitialSize(druid_initialsize);// 初始化连接大小        druidDataSource.setMaxActive(druid_maxactive); // 连接池最大使用连接数量        druidDataSource.setMinIdle(druid_minidle); // 连接池最小空闲        druidDataSource.setMaxWait(druid_maxwait); // 获取连接最大等待时间                // 打开PSCache,并且指定每个连接上PSCache的大小        druidDataSource.setPoolPreparedStatements(false);         druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(33);                //druidDataSource.setValidationQuery("SELECT 1"); // 用来检测连接是否有效的sql        druidDataSource.setTestOnBorrow(false); // 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。        druidDataSource.setTestOnReturn(false); // 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能        druidDataSource.setTestWhileIdle(false); // 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效                druidDataSource.setTimeBetweenLogStatsMillis(60000); // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒        druidDataSource.setMinEvictableIdleTimeMillis(1800000); // 配置一个连接在池中最小生存的时间,单位是毫秒        // 当程序存在缺陷时,申请的连接忘记关闭,这时候,就存在连接泄漏        // 配置removeAbandoned对性能会有一些影响,建议怀疑存在泄漏之后再打开。在上面的配置中,如果连接超过30分钟未关闭,就会被强行回收,并且日志记录连接申请时的调用堆栈。        druidDataSource.setRemoveAbandoned(false); // 打开removeAbandoned功能         druidDataSource.setRemoveAbandonedTimeout(1800); // 1800秒,也就是30分钟        druidDataSource.setLogAbandoned(false); // 关闭abanded连接时输出错误日志                // 过滤器        List<Filter> filters = new ArrayList<Filter>();        filters.add(this.getStatFilter()); // 监控        //filters.add(this.getSlf4jLogFilter()); // 日志        filters.add(this.getWallFilter()); // 防火墙        druidDataSource.setProxyFilters(filters);        log.info("连接池配置信息:"+druidDataSource.getUrl());  if (shardingRuleSupport == null || shardingRuleSupport.isEmpty()) {   log.info("............分表配置为空,使用默认的数据源............");   return druidDataSource;  }  log.info("++++++++++++加载sharding jdbc配置++++++++++++");        //包装Druid数据源  Map<String, DataSource> dataSourceMap = new HashMap<>();  //自定义一个名称为ds0的数据源名称,包装原有的Druid数据源,还可以再定义多个数据源  //因为只分表不分库,所有定义一个数据源就够了  dataSourceMap.put("ds0", druidDataSource);  //加载分表配置  ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();  //要加载所有的ShardingRuleSupport实现bean,所以用for循环加载  for (ShardingRuleSupport support : shardingRuleSupport) {   support.configRule(shardingRuleConfig);  }  //加载其他配置  Properties properties = new Properties();  //由于未使用starter的自动装配,所以手动设置,是否显示分表sql  properties.put("sql.show", sqlShow);  //返回ShardingDataSource包装的数据源  return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, properties);    } @Bean    public FilterRegistrationBean filterRegistrationBean() {        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();        WebStatFilter webStatFilter = new WebStatFilter();        filterRegistrationBean.setFilter(webStatFilter);        filterRegistrationBean.addUrlPatterns("    public StatFilter getStatFilter(){     StatFilter sFilter = new StatFilter();     //sFilter.setSlowSqlMillis(2000); // 慢sql,毫秒时间      sFilter.setLogSlowSql(false); // 慢sql日志     sFilter.setMergeSql(true); // sql合并优化处理     return sFilter;    }            public Slf4jLogFilter getSlf4jLogFilter(){     Slf4jLogFilter slFilter =  new Slf4jLogFilter();     slFilter.setResultSetLogEnabled(false);      slFilter.setStatementExecutableSqlLogEnable(false);     return slFilter;    }        public WallFilter getWallFilter(){     WallFilter wFilter = new WallFilter();     wFilter.setDbType("mysql");     wFilter.setConfig(this.getWallConfig());     wFilter.setLogViolation(true); // 对被认为是攻击的SQL进行LOG.error输出     wFilter.setThrowException(true); // 对被认为是攻击的SQL抛出SQLExcepton     return wFilter;    }        public WallConfig getWallConfig(){     WallConfig wConfig = new WallConfig();     wConfig.setDir("META-INF/druid/wall/mysql"); // 指定配置装载的目录     // 拦截配置-语句      wConfig.setTruncateAllow(false); // truncate语句是危险,缺省打开,若需要自行关闭     wConfig.setCreateTableAllow(true); // 是否允许创建表     wConfig.setAlterTableAllow(false); // 是否允许执行Alter Table语句     wConfig.setDropTableAllow(false); // 是否允许修改表     // 其他拦截配置     wConfig.setStrictSyntaxCheck(true); // 是否进行严格的语法检测,Druid SQL Parser在某些场景不能覆盖所有的SQL语法,出现解析SQL出错,可以临时把这个选项设置为false,同时把SQL反馈给Druid的开发者     wConfig.setConditionOpBitwseAllow(true); // 查询条件中是否允许有"&"、"~"、"|"、"^"运算符。     wConfig.setMinusAllow(true); // 是否允许SELECT * FROM A MINUS SELECT * FROM B这样的语句     wConfig.setIntersectAllow(true); // 是否允许SELECT * FROM A INTERSECT SELECT * FROM B这样的语句     //wConfig.setMetadataAllow(false); // 是否允许调用Connection.getMetadata方法,这个方法调用会暴露数据库的表信息     return wConfig;    }}

分表策略

主要的类

创建几个ShardingRuleSupport接口的实现Bean

@Componentpublic class DefaultShardingRuleAdapter implements ShardingRuleSupport { @Override public void configRule(ShardingRuleConfiguration shardingRuleConfiguration) {  Collection<TableRuleConfiguration> tableRuleConfigs = shardingRuleConfiguration.getTableRuleConfigs();    TableRuleConfiguration ruleConfig1 = new TableRuleConfiguration("table_one", "ds0.table_one_$->{0..9}");  ComplexShardingStrategyConfiguration strategyConfig1 = new ComplexShardingStrategyConfiguration("column_id", new MyDefaultShardingAlGorithm());  ruleConfig1.setTableShardingStrategyConfig(strategyConfig1);  tableRuleConfigs.add(ruleConfig1);  TableRuleConfiguration ruleConfig2 = new TableRuleConfiguration("table_two", "ds0.table_two_$->{0..9}");  ComplexShardingStrategyConfiguration strategyConfig2 = new ComplexShardingStrategyConfiguration("column_id", new MyDefaultShardingAlgorithm());  ruleConfig2.setTableShardingStrategyConfig(strategyConfig2);  tableRuleConfigs.add(ruleConfig2); }}
@Componentpublic class CustomShardingRuleAdapter implements ShardingRuleSupport { @Override public void configRule(ShardingRuleConfiguration shardingRuleConfiguration) {  Collection<TableRuleConfiguration> tableRuleConfigs = shardingRuleConfiguration.getTableRuleConfigs();    TableRuleConfiguration ruleConfig1 = new TableRuleConfiguration(MyCustomShardingUtil.LOGIC_TABLE_NAME, MyCustomShardingUtil.ACTUAL_DATA_nodeS);  ComplexShardingStrategyConfiguration strategyConfig1 = new ComplexShardingStrategyConfiguration(MyCustomShardingUtil.SHARDING_COLUMNS, new MyCustomShardingAlgorithm());  ruleConfig1.setTableShardingStrategyConfig(strategyConfig1);  tableRuleConfigs.add(ruleConfig1); }}

其他的分表配置类

public class MyDefaultShardingAlgorithm implements ComplexKeysshardingAlgorithm<String> { public String getShardingKey () {  return "column_id"; } @Override public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<String> shardingValue) {  Collection<String> col = new ArrayList<>();  String logicTableName = shardingValue.getLogicTableName() + "_";  Map<String, String> availableTargetNameMap = new HashMap<>();  for (String targetName : availableTargetNameMap) {   String endStr = StringUtils.substringAfter(targetName, logicTableName);   availableTargetNameMap.put(endStr, targetName);  }  int size = availableTargetNames.size();    //=,in  Collection<String> shardinGColumnValues = shardingValue.getColumnNameAndShardingValuesMap().get(this.getShardingKey());  if (shardingColumnValues != null) {   for (String shardingColumnValue : shardingColumnValues) {    String modStr = Integer.toString(Math.abs(shardingColumnValue .hashCode()) % size);    String actualTableName = availableTargetNameMap.get(modStr);    if (StringUtils.isNotEmpty(actualTableName)) {     col.add(actualTableName);    }   }  }  //between and  //shardingValue.getColumnNameAndRangeValuesMap().get(this.getShardingKey());  ... ...  //如果分表列不是有序的,则between and无意义,没有必要实现  return col; }}
public class MyCustomShardingAlgorithm extends MyDefaultShardingAlgorithm implements ComplexKeysShardingAlgorithm<String> { @Override public String getShardingKey () {  return MyCustomShardingUtil.SHARDING_COLUMNS; } @Override public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<String> shardingValue) {  Collection<String> col = new ArrayList<>();  String logicTableName = shardingValue.getLogicTableName() + "_";  Map<String, String> availableTargetNameMap = new HashMap<>();  for (String targetName : availableTargetNameMap) {   String endStr = StringUtils.substringAfter(targetName, logicTableName);   availableTargetNameMap.put(endStr, targetName);  }  Map<String, String> specialActualTableNameMap = MyCustomShardingUtil.getSpecialActualTableNameMap();    int count = (int) specialActualTableNameMap.values().stream().distinct().count();    int size = availableTargetNames.size() - count;    //=,in  Collection<String> shardingColumnValues = shardingValue.getColumnNameAndShardingValuesMap().get(this.getShardingKey());  if (shardingColumnValues != null) {   for (String shardingColumnValue : shardingColumnValues) {    String specialActualTableName = specialActualTableNameMap.get(shardingColumnValue);    if (StringUtils.isNotEmpty(specialActualTableName)) {     col.add(specialActualTableName);     continue;    }    String modStr = Integer.toString(Math.abs(shardingColumnValue .hashCode()) % size);    String actualTableName = availableTargetNameMap.get(modStr);    if (StringUtils.isNotEmpty(actualTableName)) {     col.add(actualTableName);    }   }  }  //between and  //shardingValue.getColumnNameAndRangeValuesMap().get(this.getShardingKey());  ... ...  //如果分表列不是有序的,则between and无意义,没有必要实现  return col; }}
@Componentpublic class MyCustomShardingUtil {  public static final String LOGIC_TABLE_NAME = "table_three";  public static final String SHARDING_COLUMNS = "column_name";  private static final String[] SPECIAL_NODES = new String[]{"0sp", "1sp"}; // ds0.table_three_$->{((0..9).collect{t -> t.toString()} << ['0sp','1sp']).flatten()} public static final String ACTUAL_DATA_NODES = "ds0." + LOGIC_TABLE_NAME + "_$->{((0..9).collect{t -> t.toString()} << "             + "['" + SPECIAL_NODES[0] + "','" + SPECIAL_NODES[1] + "']"             + ").flatten()}";  private static final List<String> specialList0 = new ArrayList<>(); @Value("${special.table_three.sp0.ids:null}") private void setSpecialList0(String ids) {  if (StringUtils.isBlank(ids)) {   return;  }  String[] idSplit = StringUtils.split(ids, ",");  for (String id : idSplit) {   String trimId = StringUtils.trim(id);   if (StringUtils.isEmpty(trimId)) {    continue;   }   specialList0.add(trimId);  } }  private static final List<String> specialList1 = new ArrayList<>(); @Value("${special.table_three.sp1.ids:null}") private void setSpecialList1(String ids) {  if (StringUtils.isBlank(ids)) {   return;  }  String[] idSplit = StringUtils.split(ids, ",");  for (String id : idSplit) {   String trimId = StringUtils.trim(id);   if (StringUtils.isEmpty(trimId)) {    continue;   }   specialList1.add(trimId);  } } private static class SpecialActualTableNameHolder {   private static volatile Map<String, String> specialActualTableNameMap = new HashMap<>();  static {   for (String specialId : specialList0) {    specialActualTableNameMap.put(specialId, LOGIC_TABLE_NAME + "_" + SPECIAL_NODES[0]);   }   for (String specialId : specialList1) {    specialActualTableNameMap.put(specialId, LOGIC_TABLE_NAME + "_" + SPECIAL_NODES[1]);   }  } }  public static Map<String, String> getSpecialActualTableNameMap() {  return SpecialActualTableNameHolder.specialActualTableNameMap; } }

ShardingAlgorithm接口的子接口除了ComplexKeysShardingAlgorithm,还有HintShardingAlgorithm,PreciseShardingAlgorithm,RangeShardingAlgorithm;本教程使用了更通用的ComplexKeysShardingAlgorithm接口。

配置TableRuleConfiguration类时,使用了两个参数的构造器

public TableRuleConfiguration(String logicTable, String actualDataNodes) {}

TableRuleConfiguration类还有一个参数的的构造器,没有实际数据节点,是给广播表用的

public TableRuleConfiguration(String logicTable) {}

groovy行表达式说明

ds0.table_three_$->{((0…9).collect{t -> t.toString()} << [‘0sp',‘1sp']).flatten()}

sharding-jdbc的groovy行表达式支持$->{…}或${…},为了避免与spring的占位符混淆,官方推荐使用$->{…}

(0..9) 获得0到9的集合

(0..9).collect{t -> t.toString()} 数值0到9的集合转换成字符串0到9的数组

(0..9).collect{t -> t.toString()} << ['0sp','1sp'] 字符串0到9的数组合并['0sp','1sp']数组,结果为 ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ['0sp','1sp']]

flatten() 扁平化数组,结果为 ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0sp', '1sp']

properties配置

#是否显示分表SQL,默认为falsespring.shardingsphere.props.sql.show=true#指定哪些列值入指定的分片表,多个列值以“,”分隔#column_name为9997,9998,9999的记录存入表table_three_0sp中#column_name为1111,2222,3333,4444,5555的记录存入表table_three_1sp中#其余的值哈希取模后,存入对应的table_three_模数表中special.table_three.sp0.ids=9997,9998,9999special.table_three.sp1.ids=1111,2222,3333,4444,5555

Sharding-jdbc的坑

任何SQL,只要select子句中包含动态参数,则抛出类型强转异常

禁止修改分片键,如果update的set子句中存在分片键,则不能执行sql

感谢各位的阅读,以上就是“springboot怎么配置sharding-jdbc水平分表”的内容了,经过本文的学习后,相信大家对springboot怎么配置sharding-jdbc水平分表这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: springboot怎么配置sharding-jdbc水平分表

本文链接: https://www.lsjlt.com/news/300764.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • springboot怎么配置sharding-jdbc水平分表
    这篇文章主要讲解了“springboot怎么配置sharding-jdbc水平分表”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“springboot怎么配置sharding-jdbc水平分表...
    99+
    2023-06-21
  • springboot实现以代码的方式配置sharding-jdbc水平分表
    目录关于依赖shardingsphere-jdbc-core-spring-boot-startershardingsphere-jdbc-core数据源DataSource原Dat...
    99+
    2024-04-02
  • 怎么使用sharding-jdbc实现水平分表
    这篇文章主要介绍“怎么使用sharding-jdbc实现水平分表”,在日常操作中,相信很多人在怎么使用sharding-jdbc实现水平分表问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用shardin...
    99+
    2023-06-25
  • 如何使用sharding-jdbc实现水平分库+水平分表
    这篇文章给大家分享的是有关如何使用sharding-jdbc实现水平分库+水平分表的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。分库分表策略:将id为偶数的存入到库1中,奇数存入到库2中,在每个库中,再根据学生的...
    99+
    2023-06-22
  • 使用sharding-jdbc实现水平分库+水平分表的示例代码
    前面的文章使用sharding-jdbc实现水平分表中详细记录了如何使用sharding-jdbc实现水平分表,即根据相应的策略,将一部分数据存入到表1中,一部分数据存入到表2中,...
    99+
    2024-04-02
  • 使用sharding-jdbc实现水平分表的示例代码
    目录在mysql中新建数据库sharding_db,新增两张结构一样的表student_1和student_2。添加依赖编写配置文件编写实体类编写mapper接口编写测试类执行测试在...
    99+
    2024-04-02
  • SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分库分表
    目录一、序言1、组件及版本选择2、预期目标二、代码实现(一)素材准备1、实体类2、Mapper类3、全局配置文件(二)增删查改1、保存数据2、查询列表数据3、分页查询数据4、查询详情...
    99+
    2024-04-02
  • 怎么用Sharding-Jdbc进行分库分表
    这篇文章主要介绍“怎么用Sharding-Jdbc进行分库分表”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么用Sharding-Jdbc进行分库分表”文章能帮助大家解决问题。1. Shardin...
    99+
    2023-06-28
  • SpringBoot 如何使用sharding jdbc进行分库分表
    目录基于4.0版本,Springboot2.1在pom里确保有如下引用里面我profiles.active了另一个之后手工把表都建好写个测试代码需要注意一个坑基于4.0版本,Spri...
    99+
    2024-04-02
  • SpringBoot怎么整合sharding-jdbc实现分库分表与读写分离
    本篇内容主要讲解“SpringBoot怎么整合sharding-jdbc实现分库分表与读写分离”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringBoot怎么整合sharding-jdbc...
    99+
    2023-06-25
  • SpringBoot整合sharding-jdbc实现自定义分库分表的实践
    目录一、前言二、简介1、分片键2、分片算法三、程序实现一、前言 SpringBoot整合sharding-jdbc实现分库分表与读写分离 本文将通过自定义算法来实现定制化的分库分表来...
    99+
    2024-04-02
  • SpringBoot中怎么利用Sharding-JDBC实现MySQL8读写分离
    这篇文章将为大家详细讲解有关SpringBoot中怎么利用Sharding-JDBC实现MySQL8读写分离,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。一.前言这是一个基于SpringBo...
    99+
    2023-06-20
  • SpringBoot整合sharding-jdbc实现分库分表与读写分离的示例
    目录一、前言二、数据库表准备三、整合四、docker-compose部署mysql主从五、本文案例demo源码一、前言 本文将基于以下环境整合sharding-jdbc实现分库分表与...
    99+
    2024-04-02
  • SpringBoot整合sharding-jdbc实现自定义分库分表的方法是什么
    这篇文章主要讲解了“SpringBoot整合sharding-jdbc实现自定义分库分表的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot整合sharding-j...
    99+
    2023-06-25
  • MongoDB 3.4中怎么配置sharding分片
    这篇文章给大家介绍MongoDB 3.4中怎么配置sharding分片,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。 1. 创建配置服务副本集创建...
    99+
    2024-04-02
  • mysql水平分表后怎么查询
    当使用水平分表技术后,查询语句的写法会发生一些变化。以下是一些常用的查询示例: 查询单个表: SELECT * FROM...
    99+
    2023-10-27
    mysql
  • Mysql中怎么实现水平分表与垂直分表
    本篇文章为大家展示了Mysql中怎么实现水平分表与垂直分表,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。水平分表:如上图所示:另外三张表表结构是一样的  ...
    99+
    2024-04-02
  • mysql中怎么实现水平分表和垂直分表
    本篇文章为大家展示了mysql中怎么实现水平分表和垂直分表,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。 什么是数据库分区? 数据库分区是一种物理数据库设计技术...
    99+
    2024-04-02
  • springboot+mybatis拦截器方法实现水平分表操作
    目录1.前言2.MyBatis 允许使用插件来拦截的方法3、Interceptor接口 4分表实现4.1、大体思路4.2.1 Mybatis如何找到我们新增的拦截...
    99+
    2022-11-13
    springboot+mybatis拦截器 springboot+mybatis实现水平分表操作
  • mysql中怎么实现水平切分
    今天就跟大家聊聊有关mysql中怎么实现水平切分,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。方法一:使用MD5哈希  做法是对UID进行md5加密...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作