ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

dynamic + shardingsphere(4.1.1) 实现动态分库分表

2022-07-13 15:01:08  阅读:204  来源: 互联网

标签:分库 4.1 shardingsphere org dynamic datasource spring import com


1. 主要依赖:
<dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.3.2</version> </dependency> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.1</version> </dependency> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-namespace</artifactId> <version>4.1.1</version> </dependency>

2. 数据库配置如下:

spring.datasource.dynamic.primary=redisDB
spring.datasource.dynamic.datasource.redisDB.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.redisDB.url=jdbc:mysql://10.95.35.103:3306/csc_siebel_api_call?characterEncoding=UTF-8&useUnicode=true&useSSL=false&serverTimezone=GMT
spring.datasource.dynamic.datasource.redisDB.username=cscsitprd
spring.datasource.dynamic.datasource.redisDB.password=Cscs23tpr#d
spring.datasource.dynamic.datasource.campaignDB.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.campaignDB.url=jdbc:mysql://10.95.35.226:3306/CSC_MBHK_CAMPAIGN?characterEncoding=UTF-8&useUnicode=true&useSSL=false&serverTimezone=GMT
spring.datasource.dynamic.datasource.campaignDB.username=cdcmbsit
spring.datasource.dynamic.datasource.campaignDB.password=Cdcmb#sit123
spring.datasource.dynamic.datasource.memberDB.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.memberDB.url=jdbc:mysql://10.95.35.226:3306/CSC_MBHK_MEMBER?characterEncoding=UTF-8&useUnicode=true&useSSL=false&serverTimezone=GMT
spring.datasource.dynamic.datasource.memberDB.username=cdcmbsit
spring.datasource.dynamic.datasource.memberDB.password=Cdcmb#sit123

spring.shardingsphere.datasource.names=campaign-db
spring.shardingsphere.datasource.campaign-db.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.campaign-db.driverClassName=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.campaign-db.url=${spring.datasource.dynamic.datasource.campaignDB.url}
spring.shardingsphere.datasource.campaign-db.username=${spring.datasource.dynamic.datasource.campaignDB.username}
spring.shardingsphere.datasource.campaign-db.password=${spring.datasource.dynamic.datasource.campaignDB.password}

refreshCampaignContact.filterSwitch = true
# 开启打印分表sql,生产要关闭false
spring.shardingsphere.props.sql.show=true
#分表
spring.shardingsphere.sharding.tables.CUSTOMER_CAMPAIGN_CONTACT.actualDataNodes=campaign-db.CUSTOMER_CAMPAIGN_CONTACT_$->{0..63}
# 分表字段 spring.shardingsphere.sharding.tables.CUSTOMER_CAMPAIGN_CONTACT.table-strategy.standard.sharding-column=CON_PER_ID
# 实现分表规则类:-- HashModShardingAlgorithm spring.shardingsphere.sharding.tables.CUSTOMER_CAMPAIGN_CONTACT.table-strategy.standard.precise-algorithm-class-name=com.aswatson.conf.HashModShardingAlgorithm
# 注释的是,表达式方法分表,但是我们要自己增加逻辑,所以做成实现分表规则类。 #spring.shardingsphere.sharding.tables.CUSTOMER_CAMPAIGN_CONTACT.tableStrategy.inline.shardingColumn=CON_PER_ID #spring.shardingsphere.sharding.tables.CUSTOMER_CAMPAIGN_CONTACT.tableStrategy.inline.algorithmExpression=CUSTOMER_CAMPAIGN_CONTACT_$->{(CON_PER_ID.hashCode()& Integer.MAX_VALUE) % 64} spring.shardingsphere.sharding.tables.CUSTOMER_LOY_CAM_SEG.actualDataNodes=campaign-db.CUSTOMER_LOY_CAM_SEG_$->{0..63} spring.shardingsphere.sharding.tables.CUSTOMER_LOY_CAM_SEG.table-strategy.standard.sharding-column=CONTACT_ID spring.shardingsphere.sharding.tables.CUSTOMER_LOY_CAM_SEG.table-strategy.standard.precise-algorithm-class-name=com.aswatson.conf.HashModShardingAlgorithm spring.datasource.dynamic.druid.initial-size = 5 spring.datasource.dynamic.druid.min-idle = 5 spring.datasource.dynamic.druid.max-active = 30 spring.datasource.dynamic.druid.max-wait = 6000 spring.datasource.dynamic.druid.time-between-eviction-runs-millis = 60000 spring.datasource.dynamic.druid.min-evictable-idle-time-millis = 300000 spring.datasource.dynamic.druid.validation-query = SELECT 1 FROM DUAL spring.datasource.dynamic.druid.test-while-idle = true spring.datasource.dynamic.druid.test-on-borrow = false spring.datasource.dynamic.druid.test-on-return = false

3. 配置 ShardingDataSourceConfig类:

package com.aswatson.conf;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
 
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Map;
 
@Configuration
@AutoConfigureAfter({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class ShardingDataSourceConfig {

    @Resource
    private DynamicDataSourceProperties properties;

    //@Lazy
    @Resource(name = "shardingDataSource")
    private DataSource shardingSphereDataSource;

   @Bean public DynamicDataSourceProvider dynamicDataSourceProvider() { Map<String, DataSourceProperty> datasourceMap = properties.getDatasource(); return new AbstractDataSourceProvider() { @Override public Map<String, DataSource> loadDataSources() { Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);
          // @DS(campaign-db-sharding) 就是注入的数据源,分库分表的时候,在mapper层注入. dataSourceMap.put("campaign-db-sharding", shardingSphereDataSource); return dataSourceMap; } }; } /** * 将动态数据源设置为首选的,当spring存在多个数据源时, 自动注入的是首选的对象设置为主要的数据源之后,就支持shardingjdbc原生的配置方式 */ @Primary @Bean public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) { DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); dataSource.setPrimary(properties.getPrimary()); dataSource.setStrict(properties.getStrict()); dataSource.setStrategy(properties.getStrategy()); dataSource.setProvider(dynamicDataSourceProvider); dataSource.setP6spy(properties.getP6spy()); dataSource.setSeata(properties.getSeata()); return dataSource; } }

4. 配置分表的规则(简单精准分表策略):

package com.aswatson.conf;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import java.util.Collection;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

/**
 * @Author Tim
 * @Date 2022/6/30 11:52
 */
@Slf4j
public class HashModShardingAlgorithm implements PreciseShardingAlgorithm {

    // 通过Apollo client获取是否需要分表开关,不需要分表,通过availableTargetNames 截取 "_num"前的表
    public static String shardingTableSwitch = "sharding.table.switch";
    public static String nameSpace = "cdc-common";

    @Override
    public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) {
        Comparable value = shardingValue.getValue();
        int hashValue = value.hashCode();
        int availableTargetNamesLen = availableTargetNames.size();
        int targetNamesIdx = Math.abs(hashValue) % availableTargetNamesLen;
        Object[] availableTargetNamesArr = availableTargetNames.toArray(new Object[0]);
        String tableName = String.valueOf(availableTargetNamesArr[targetNamesIdx]);
        log.info("redisService-doSharding-tableName: {}", tableName);
        return getActualTable(tableName);
    }

    private String getActualTable(String tableName) {
        Config config = ConfigService.getConfig(nameSpace);
        boolean tableShardingSwitch = Boolean.parseBoolean(config.getProperty(shardingTableSwitch, "false"));
        if (!tableShardingSwitch) {
            String actualTable = tableName.replaceAll("\\d+","");
            return actualTable.substring(0, actualTable.length()-1);
        }
        log.info("redisService-getActualTable: tableShardingSwitch={}, tableName={}", tableShardingSwitch, tableName);
        return tableName;
    }

}

5.  分库分表使用,在mapper上增加注入的数据源名

package com.aswatson.infrastructure.dao.campaignDao.mapper;

import com.aswatson.infrastructure.dao.campaignDao.model.CustomerCampaignContactPO;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

@Mapper
@DS("campaign-db-sharding")
public interface CustomerCampaignContactMapper extends BaseMapper<CustomerCampaignContactPO> {

    @Select("SELECT DISTINCT SEG_NUM FROM CUSTOMER_LOY_CAM_SEG WHERE CONTACT_ID = #{contactId}")
    List<String> getCustomerLoyCampaignSegments(@Param("contactId") String contactId);

    List<CustomerCampaignContactPO> getCustomerContactLoyByConPerIdAndFilter(@Param("contactId") String contactId);

}

6. 其他的数据源:

package com.aswatson.infrastructure.dao.memberDao.mapper;

import com.aswatson.infrastructure.dao.memberDao.model.CustomerLoyCardPO;
import com.aswatson.infrastructure.dao.memberDao.model.CustomerLoyContactSplit1PO;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author albert.yang
 * @since 2020-04-09
 */
@Mapper
@DS("memberDB")
public interface CustomerLoyContactSplit1Mapper extends BaseMapper<CustomerLoyContactSplit1PO> {

    List<CustomerLoyCardPO> selectMobile(@Param("buId") String buId, @Param("mobile") String mobile,
        @Param("mobile2") String mobile2);
}

7. 注意的是,项目启动时候会报错:

package com.aswatson;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import io.micrometer.core.instrument.MeterRegistry;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.scheduling.annotation.EnableScheduling;

@Configuration
//启动类要注意排除自动注入的数据源
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class}, scanBasePackages = {"com.aswatson.*"})
@ComponentScan({"com.aswatson.*"})
@MapperScan("com.aswatson.infrastructure.dao.*")
//@EnableDiscoveryClient
@EnableScheduling
public class RedisServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisServerApplication.class, args);
    }

    @Bean MeterRegistryCustomizer<MeterRegistry> configurer(@Value("${spring.application.name}") String applicationName) {
        return registry -> registry.config().commonTags("application", applicationName);
    }

}

 

 

8. 写个测试接口就可以测试了:

 

标签:分库,4.1,shardingsphere,org,dynamic,datasource,spring,import,com
来源: https://www.cnblogs.com/lgg20/p/16473882.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有