Sprig boot 2.1 sharding 分表

本文介绍 spring boot 2.1 与 dangdang 分表插件进行整合

maven配置

当前项目使用的是 jpa 与 durid

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>com.dangdang</groupId>
    <artifactId>sharding-jdbc-core</artifactId>
    <version>1.5.4.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.9</version>
</dependency>

配置文件

spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
spring.datasource.databaseName=monitor_image
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

sharding 分表类

项目的需求是按照日期分表,一天一个,已下划线加当天的日期,例如:test_20190620、test_20190621

package com.truthso.monitor.sharding;

import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm;
import com.google.common.collect.Range;
import com.truthso.monitor.utils.DateUtil;

import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;

/**
 * 日期分表
 */
public class DateShardingAlgorithm implements SingleKeyTableShardingAlgorithm<String> {

    @Override
    public String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<String> shardingValue) {
        String logicTableName = shardingValue.getLogicTableName();
        String date = shardingValue.getValue();
        return String.format("%s_%s", logicTableName, date);
    }

    @Override
    public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<String> shardingValue) {
        String logicTableName = shardingValue.getLogicTableName();
        Date today = new Date();
        Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());
        for (String date : shardingValue.getValues()) {
            Date day = DateUtil.str2Date(date, DateUtil.PATTERN_DATE_SHORT);
            if (day.after(today)) {
                continue;
            }
            result.add(String.format("%s_%s", logicTableName, date));
        }

        return result;
    }

    @Override
    public Collection<String> doBetweenSharding(Collection<String> availableTargetNames, ShardingValue<String> shardingValue) {
        String logicTableName = shardingValue.getLogicTableName();
        Range<String> range = shardingValue.getValueRange();
        String lower = range.lowerEndpoint();
        String upper = range.upperEndpoint();
        Date start = DateUtil.str2Date(lower, DateUtil.PATTERN_DATE_SHORT);
        Date end = DateUtil.str2Date(upper, DateUtil.PATTERN_DATE_SHORT);
        Date today = new Date();
        if (end.after(today)) {
            end = today;
            upper = DateUtil.formatDate(DateUtil.PATTERN_DATE_SHORT);
        }
        LinkedHashSet<String> result = new LinkedHashSet<>(availableTargetNames.size());
        result.add(String.format("%s_%s", logicTableName, lower));
        while (start.before(end)) {
            String day = DateUtil.date2Str(start, DateUtil.PATTERN_DATE_SHORT);
            result.add(String.format("%s_%s", logicTableName, day));
            start = DateUtil.addDate(start, 1);
        }
        result.add(String.format("%s_%s", logicTableName, upper));

        return result;
    }
}
 

DateUtil.PATTERN_DATE_SHORT) 就是 yyyyMMdd 的格式

另外需要增加congfig来加载我们的分表策略

package com.truthso.monitor.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.dangdang.ddframe.rdb.sharding.api.ShardingDataSourceFactory;
import com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
import com.mysql.cj.jdbc.Driver;
import com.truthso.monitor.sharding.DateShardingAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DataSourceConfiguration {

    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Bean
    public DataSource getDataSource() throws SQLException {
        return buildDataSource();
    }

    private DataSource buildDataSource() throws SQLException {

        Map<String, DataSource> dsMap = new HashMap<>();
        DataSource ds = createDataSource(url, username, password);
        dsMap.put("druid", ds);

        DataSourceRule dataSourceRule = new DataSourceRule(dsMap);
		// 这里写入的就是具体的表的前缀
        TableRule monitorResultRule = TableRule.builder("image_old_compare")
                .dataSourceRule(dataSourceRule)
                .dynamic(true)
                .tableShardingStrategy(new TableShardingStrategy("datestr", new DateShardingAlgorithm()))
                .build();

        ShardingRule shardingRule = ShardingRule.builder()
                .dataSourceRule(dataSourceRule)
                .tableRules(Arrays.asList(monitorResultRule))
                .build();

        DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule);

        return dataSource;
    }

    private static DataSource createDataSource(final String dataSourceName, final String username, final String password) {
        DruidDataSource result = new DruidDataSource();
        result.setDriverClassName(Driver.class.getName());
        result.setUrl(dataSourceName);
        result.setUsername(username);
        result.setPassword(password);
        return result;
    }

}

表结构的设计

Sprig boot 2.1 sharding 分表_第1张图片
重要的地方 就是分表的字段,比如我日期分表的字段就是 datastr,所有的表都是一样的结构,但是不同的每个表的datestr字段都是当前表的后缀,比如分表 test_20190603 那么 这个表的 datestr 字段的值都是 20190603 不然会查询不出来。

使用

就正常使用的方式就行,比如添加

ImageOldCompare compare = new ImageOldCompare();
compare.setSamplePageUrl(samplePageUrl);
compare.setSampleImageUrl(sampleImageUrl);
compare.setSim(sim);
compare.setResultImageUrl(urls[0]);
compare.setResultPageUrl(pageUrl);
compare.setResultImageSource(resultInfo.source);
compare.setDatestr(DateUtil.date2Str(new Date(), DateUtil.PATTERN_DATE_SHORT));

dao.save(compare);

注意 每次的操作,datestr 字段都需要设置要操作的表的日期,不然会报错。其余所有的操作和不分表的操作一样,包括分页之类的。

遇到的问题

  1. 在使用的时候,需要分表的表的操作没有问题,但是同一个数据库不需要分表的表会报错,说找不到逻辑分表的策略什么的,经过排查,将 sharding 的版本从 1.5.4 提升到了 1.5.4.1 (目前最新版)就没有出现过问题了。
  2. 如果使用的 durid 版本过低也会有问题,目前上述的配置在我的项目中能够很好的使用。

你可能感兴趣的:(spring-boot)