(springboot系列)springboot+sharding+动态数据源

1. sharding简介

ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,目前已在阿帕奇孵化成功,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,这里主要介绍shardingjdbc,文档地址 https://shardingsphere.apache.org/document/current/cn/overview/

2. 使用

1.引入maven包

这里不适用start包,而直接使用原包,这里还需要排除sharding的mysql连接器,使用自己的连接器

<!-- https://mvnrepository.com/artifact/io.shardingsphere/sharding-jdbc-core -->
<dependency>
    <groupId>io.shardingsphere</groupId>
    <artifactId>sharding-jdbc-core</artifactId>
    <version>3.1.0</version>
    <exclusions>
        <exclusion>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </exclusion>
    </exclusions>
</dependency>

2.配置

sharding和动态数据源整合一起,因为sharding会全局解析所有sql,在某些情况下mybatis能解析的sql语句sharding是没办法解析的,会导致以前的业务sql出现问题,所以我们通过动态数据源和注解的形式标注哪些sql需要使用sharding的数据源,灵活配置

DynamicDataSource

/**
 * 动态数据源
 * Created by tyf on 2019/9/25 0025
 */
public class DynamicDataSource extends AbstractRoutingDataSource {


    //用来保存数据源与获取数据源
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(new HashMap<>(targetDataSources));
        super.afterPropertiesSet();
    }

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }
}

ShardingDataSourceAspect 动态数据源aop切面,使用springboot的方式

/**
 * 动态数据源aop切面
 * Created by tyf on 2019/9/25 0025
 */
@Aspect
public class ShardingDataSourceAspect {

    @Around(ExecutionConstant.CONTROLLER + "||" + ExecutionConstant.SERVICE)
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 获取方法名
        String methodName = point.getSignature().getName();
        // 反射获取目标类
        Class<?> targetClass = point.getTarget().getClass();
        // 拿到方法对应的参数类型
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes();
        // 根据类、方法、参数类型(重载)获取到方法的具体信息
        Method method = targetClass.getMethod(methodName, parameterTypes);

        final ShardingDataSource methodAnnotation = AnnotationUtils.findAnnotation(method, ShardingDataSource.class);
        final ShardingDataSource classAnnotation = AnnotationUtils.findAnnotation(targetClass, ShardingDataSource.class);

        //当类和方法上都没注解的时候,跳过
        if (methodAnnotation == null && classAnnotation == null) {
            return point.proceed();
        }

        DynamicDataSource.setDataSource(DataSourceNames.SHARDING);
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
        }
    }

}

ShardingDataSource,注解

/**
 * Created by tyf on 2019/9/25 0025
 */
@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ShardingDataSource {
}

DataSourceNames常量

/**
 * Created by tyf on 2019/9/25 0025
 */
public interface DataSourceNames {

    String DEFAULT = "default";
    String SHARDING = "sharding";

}

ShardingConfiguration,sharding配置类,将配置抽象在基础包中,只有当业务项目有ShardingRuleConfiguration类之后才会加载sharding配置类

@Configuration
@DependsOn("springTools")
@ConditionalOnBean({ShardingRuleConfiguration.class})
public class ShardingConfiguration {


    /**
     * 代理切面类
     *
     * @return
     */
    @Bean
    public ShardingDataSourceAspect shardingDataSourceAspect() {
        return new ShardingDataSourceAspect();
    }

    /**
     * 多数据源,默认为springboot数据源,使用{@link ShardingDataSource} 标记为sharding数据源
     *
     * @param dataSourceProperties
     * @param shardingRuleConfiguration
     * @return
     * @throws SQLException
     */
    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSourceProperties dataSourceProperties, ShardingRuleConfiguration shardingRuleConfiguration) throws SQLException {
        //初始化springboot数据源
        final DataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().build();

        //设置动态数据源
        Map<String, DataSource> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.DEFAULT, dataSource);
        targetDataSources.put(DataSourceNames.SHARDING, getShardingDataSource(dataSource, shardingRuleConfiguration));
        return new DynamicDataSource(dataSource, targetDataSources);
    }


    private DataSource getShardingDataSource(DataSource dataSource, ShardingRuleConfiguration shardingRuleConfiguration) throws SQLException {
        final Properties properties = new Properties();

        // 获取数据源对象
        final DataSource shardingDatasource = ShardingDataSourceFactory.createDataSource(ImmutableMap.of("ds0", dataSource),
                shardingRuleConfiguration, new ConcurrentHashMap(), properties);
        return shardingDatasource;
    }

}

在业务项目中,你只需要配置ShardingRuleConfiguration即可开箱使用sharding了,例如

    /**
     * sharding分片规则
     *
     * @return
     */
    @Bean
    @Primary
    public ShardingRuleConfiguration shardingRuleConfiguration() {
        final ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
        TableRuleConfiguration sappPaperRankingTableRuleConfig = new TableRuleConfiguration();
        sappPaperRankingTableRuleConfig.setLogicTable("sapp_paper_ranking");

        //选需要分片的对应的库和表
        sappPaperRankingTableRuleConfig.setActualDataNodes("ds0.sapp_paper_ranking_0${1..9},ds0.sapp_paper_ranking_${10..31}");
        // 配置分库 + 分表策略
        sappPaperRankingTableRuleConfig.setDatabaseShardingStrategyConfig(new NoneShardingStrategyConfiguration());
        sappPaperRankingTableRuleConfig.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration(
                "create_date", new SappPaperRankingPreciseShardingAlgorithm()));
        // 配置分片规则
        shardingRuleConfiguration.getTableRuleConfigs().add(sappPaperRankingTableRuleConfig);
        return shardingRuleConfiguration;
    }
    
    
    /**
     * 精确分片算法,=与IN进行分片
     */
    public class SappPaperRankingPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {
        @Override
        public String doSharding(Collection<String> tableNames/*表名*/, PreciseShardingValue<Integer> shardingValue /*分片键*/) {
    
            final Integer uid = shardingValue.getValue();
            
            /*省略*/
            
            throw new UnsupportedOperationException();
        }
    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容