最近版本,基于sharding-jdbc,druid,mybatisplus,springboot的分库分表,读写分离和sql监控功能实现,简单易用

最近版本,基于sharding-jdbc,druid,mybatisplus,springboot的分库分表,读写分离和sql监控功能实现,简单易用

参考工程地址:https://gitee.com/proLeo/ray,分支dev-2.0,部分配置如下

  • druid starter和shardingsphere starter均使用较新版本

        3.1.0
        2.0.0
        1.1.22
        4.1.0




            
                com.alibaba.spring.boot
                dubbo-spring-boot-starter
                ${dubbo.starter.version}
            
            
            
                com.alibaba
                druid-spring-boot-starter
                ${druid.starter.version}
            
            
            
                com.baomidou
                mybatis-plus-boot-starter
                ${mybatis-plus.version}
            
            
                com.baomidou
                mybatis-plus-generator
                ${mybatis-plus.version}
            
            
            
                org.apache.shardingsphere
                sharding-jdbc-spring-boot-starter
                ${shardingsphere.version}
            
            
            
                org.apache.shardingsphere
                sharding-transaction-xa-core
                ${shardingsphere.version}
            
            
            
                org.apache.shardingsphere
                sharding-transaction-base-seata-at
                ${shardingsphere.version}
            
  • application-dev.yml配置,配置了分库分表和读写分离,mysql主从可以用项目中的docker/database/master-slave/docker-compose.yml快速搭建
spring:
  datasource:
    druid:
      # 连接池的配置信息
      # 初始化大小,最小,最大
      initial-size: 5
      min-idle: 5
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      # 打开PSCache,并且指定每个连接上PSCache的大小
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
      web-stat-filter:
        enabled: true
        url-pattern: "/*"
        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
        session-stat-enable: true
        session-stat-max-count: 1000
      # 配置DruidStatViewServlet
      stat-view-servlet:
        enabled: true
        url-pattern: "/druid/*"
        # IP白名单(没有配置或者为空,则允许所有访问)
        # allow: 127.0.0.1,192.168.46.120
        # IP黑名单 (存在共同时,deny优先于allow)
        # deny: 192.168.46.121
        #  禁用HTML页面上的“Reset All”功能
        reset-enable: false
        # 登录名
        login-username: admin
        # 登录密码
        login-password: 123456

  dubbo:
    application:
      name: ray-iflow-rpc-service
      registry: zookeeper://192.168.125.161:2183
    protocol:
      id: dubbo
      name: dubbo
      port: 20881
      status: server
  #sharding配置
  shardingsphere:
    dataSource:
      names: master0,master1,master0-slave1,master0-slave2,master1-slave1
      master0:
        type: com.alibaba.druid.pool.DruidDataSource
        #自定义的配置项,因为type为DruidDataSource,需要特别配置filters,否则shardingsphere注入的DruidDataSource不含filters,不能实现相关的监控功能
        filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter
        url: jdbc:mysql://192.168.125.161:36005/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT
        username: root
        #使用了自定义的AES对称加密,启动时需要添加启动参数-Denc.key=${自定义的key},用ray-common中的AESUtil加密
        #如果不需要去除enc:前缀即可
        password: enc:jEhi6SfY38B7rIB9wrFZ1w==
        driver-class-name: com.mysql.cj.jdbc.Driver
      master0-slave1:
        type: com.alibaba.druid.pool.DruidDataSource
        filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter
        url: jdbc:mysql://192.168.125.161:36006/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT
        username: root
        password: enc:jEhi6SfY38B7rIB9wrFZ1w==
        driver-class-name: com.mysql.cj.jdbc.Driver
      master0-slave2:
        type: com.alibaba.druid.pool.DruidDataSource
        filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter
        url: jdbc:mysql://192.168.125.161:36007/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT
        username: root
        password: enc:jEhi6SfY38B7rIB9wrFZ1w==
        driver-class-name: com.mysql.cj.jdbc.Driver
      master1:
        type: com.alibaba.druid.pool.DruidDataSource
        filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter
        url: jdbc:mysql://192.168.125.161:36008/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT
        username: root
        password: enc:jEhi6SfY38B7rIB9wrFZ1w==
        driver-class-name: com.mysql.cj.jdbc.Driver
      master1-slave1:
        type: com.alibaba.druid.pool.DruidDataSource
        filters: com.alibaba.druid.filter.stat.StatFilter,com.alibaba.druid.wall.WallFilter,com.alibaba.druid.filter.logging.Log4j2Filter
        url: jdbc:mysql://192.168.125.161:36009/iflow?autoReconnect=true&useUnicode=true&createDatabaseIfNotExist=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT
        username: root
        password: enc:jEhi6SfY38B7rIB9wrFZ1w==
        driver-class-name: com.mysql.cj.jdbc.Driver
    #分库分表
    sharding:
      tables:
        operation:
          #此处有坑,如果配置了master-slave-rules则需要用其中配置的数据源
          #actual-data-nodes: master$->{0..1}.operation_$->{0..1}
          #表规则
          actual-data-nodes: db_master_$->{0..1}.operation_$->{0..1}
          #分库策略
          database-strategy:
            inline:
              sharding-column: assess_status
              #和上面同样的坑,如果配置了master-slave-rules则需要用其中配置的数据源,
              #但是io.shardingsphere的starter确可以直接取datasource中的数据源
              algorithm-expression: db_master_$->{assess_status%2}
          #分表策略
          table-strategy:
            inline:
              sharding-column: id
              algorithm-expression: operation_$->{id % 2}
      #      default-key-generator:
      #        type: SnowflakeShardingKeyGenerator
      #        column: id
      master-slave-rules:
        db_master_0:
          name: m0s2
          master-data-source-name: master0
          slave-data-source-names: master0-slave1,master0-slave2
        db_master_1:
          name: m1s1
          master-data-source-name: master1
          slave-data-source-names: master1-slave1

    props:
      sql:
        show: true

server:
  tomcat:
    uri-encoding: UTF-8
  port: 8085

mybatis-plus:
  datasource: dataSource
  mapper-locations: classpath*:/mappers/**/**Mapper.xml
  typeAliasesPackage: com.mrray.ray.iflow.dao.base.model
  configuration:
    cache-enabled: false




  • 自定义sharding-jdbc配置替换sharding-jdbc-spring-boot-starter中的SpringBootConfiguration,不然要掉坑
package com.mrray.ray.common.sharding;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.google.common.base.Preconditions;
import com.mrray.ray.common.SpringContextUtil;
import org.apache.shardingsphere.core.yaml.swapper.MasterSlaveRuleConfigurationYamlSwapper;
import org.apache.shardingsphere.core.yaml.swapper.ShardingRuleConfigurationYamlSwapper;
import org.apache.shardingsphere.core.yaml.swapper.impl.ShadowRuleConfigurationYamlSwapper;
import org.apache.shardingsphere.encrypt.yaml.swapper.EncryptRuleConfigurationYamlSwapper;
import org.apache.shardingsphere.shardingjdbc.api.EncryptDataSourceFactory;
import org.apache.shardingsphere.shardingjdbc.api.MasterSlaveDataSourceFactory;
import org.apache.shardingsphere.shardingjdbc.api.ShadowDataSourceFactory;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.apache.shardingsphere.shardingjdbc.spring.boot.common.SpringBootPropertiesConfigurationProperties;
import org.apache.shardingsphere.shardingjdbc.spring.boot.encrypt.EncryptRuleCondition;
import org.apache.shardingsphere.shardingjdbc.spring.boot.encrypt.SpringBootEncryptRuleConfigurationProperties;
import org.apache.shardingsphere.shardingjdbc.spring.boot.masterslave.MasterSlaveRuleCondition;
import org.apache.shardingsphere.shardingjdbc.spring.boot.masterslave.SpringBootMasterSlaveRuleConfigurationProperties;
import org.apache.shardingsphere.shardingjdbc.spring.boot.shadow.ShadowRuleCondition;
import org.apache.shardingsphere.shardingjdbc.spring.boot.shadow.SpringBootShadowRuleConfigurationProperties;
import org.apache.shardingsphere.shardingjdbc.spring.boot.sharding.ShardingRuleCondition;
import org.apache.shardingsphere.shardingjdbc.spring.boot.sharding.SpringBootShardingRuleConfigurationProperties;
import org.apache.shardingsphere.spring.boot.datasource.DataSourcePropertiesSetterHolder;
import org.apache.shardingsphere.spring.boot.util.DataSourceUtil;
import org.apache.shardingsphere.spring.boot.util.PropertyUtil;
import org.apache.shardingsphere.transaction.spring.ShardingTransactionTypeScanner;
import org.apache.shardingsphere.underlying.common.config.inline.InlineExpressionParser;
import org.apache.shardingsphere.underlying.common.exception.ShardingSphereException;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.jndi.JndiObjectFactoryBean;

import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 自定义shardingsphere配置,实际拷贝自原配置文件,只做少量改动
 *
 * @author lyc
 **/
@Configuration
@ComponentScan({"org.apache.shardingsphere.spring.boot.converter"})
@EnableConfigurationProperties({SpringBootShardingRuleConfigurationProperties.class, SpringBootMasterSlaveRuleConfigurationProperties.class, SpringBootEncryptRuleConfigurationProperties.class, SpringBootPropertiesConfigurationProperties.class, SpringBootShadowRuleConfigurationProperties.class})
@ConditionalOnProperty(
        prefix = "spring.shardingsphere",
        name = {"enabled"},
        havingValue = "true",
        matchIfMissing = true
)
@AutoConfigureBefore({DruidDataSourceAutoConfigure.class, DataSourceAutoConfiguration.class})
public class MyShardingsphereConfig implements EnvironmentAware {
    private final SpringBootShardingRuleConfigurationProperties shardingRule;
    private final SpringBootMasterSlaveRuleConfigurationProperties masterSlaveRule;
    private final SpringBootEncryptRuleConfigurationProperties encryptRule;
    private final SpringBootShadowRuleConfigurationProperties shadowRule;
    private final SpringBootPropertiesConfigurationProperties props;
    private final Map dataSourceMap = new LinkedHashMap();
    private static final String JNDI_NAME = "jndi-name";
    private static final String DRUID_FILTER_PREFIX = "filters";

    /**
     * 配置属性自动填充
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(SpringContextUtil.class)
    public SpringContextUtil springContextUtil() {
        return new SpringContextUtil();
    }

    @Bean
    @Conditional({ShardingRuleCondition.class})
    public DataSource shardingDataSource() throws SQLException {
        return ShardingDataSourceFactory.createDataSource(dataSourceMap, (new ShardingRuleConfigurationYamlSwapper()).swap(shardingRule), props.getProps());
    }

    @Bean
    @Conditional({MasterSlaveRuleCondition.class})
    public DataSource masterSlaveDataSource() throws SQLException {
        return MasterSlaveDataSourceFactory.createDataSource(dataSourceMap, (new MasterSlaveRuleConfigurationYamlSwapper()).swap(masterSlaveRule), props.getProps());
    }

    @Bean
    @Conditional({EncryptRuleCondition.class})
    public DataSource encryptDataSource() throws SQLException {
        return EncryptDataSourceFactory.createDataSource((DataSource) dataSourceMap.values().iterator().next(), (new EncryptRuleConfigurationYamlSwapper()).swap(encryptRule), props.getProps());
    }

    @Bean
    @Conditional({ShadowRuleCondition.class})
    public DataSource shadowDataSource() throws SQLException {
        return ShadowDataSourceFactory.createDataSource(dataSourceMap, (new ShadowRuleConfigurationYamlSwapper()).swap(shadowRule), props.getProps());
    }

    @Bean
    public ShardingTransactionTypeScanner shardingTransactionTypeScanner() {
        return new ShardingTransactionTypeScanner();
    }

    @Override
    public final void setEnvironment(Environment environment) {
        String prefix = "spring.shardingsphere.datasource.";

        for (String dsName : getDataSourceNames(environment, prefix)) {
            try {
                dataSourceMap.put(dsName, getDataSource(environment, prefix, dsName));
            } catch (ReflectiveOperationException reflectiveOperationException) {
                throw new ShardingSphereException("Can't find datasource type!", reflectiveOperationException);
            } catch (NamingException namingException) {
                throw new ShardingSphereException("Can't find JNDI datasource!", namingException);
            } catch (SQLException sqlException) {
                throw new ShardingSphereException("set druidDatasource filters failed!", sqlException);
            }
        }

    }

    private List getDataSourceNames(Environment environment, String prefix) {
        StandardEnvironment standardEnv = (StandardEnvironment) environment;
        standardEnv.setIgnoreUnresolvableNestedPlaceholders(true);
        return null == standardEnv.getProperty(prefix + "name") ? (new InlineExpressionParser(standardEnv.getProperty(prefix + "names"))).splitAndEvaluate() : Collections.singletonList(standardEnv.getProperty(prefix + "name"));
    }

    private DataSource getDataSource(Environment environment, String prefix, String dataSourceName) throws ReflectiveOperationException, NamingException, SQLException {
        Map dataSourceProps = (Map) PropertyUtil.handle(environment, prefix + dataSourceName.trim(), Map.class);
        Preconditions.checkState(!dataSourceProps.isEmpty(), "Wrong datasource properties!");
        if (dataSourceProps.containsKey(JNDI_NAME)) {
            return getJndiDataSource(dataSourceProps.get(JNDI_NAME).toString());
        } else {
            DataSource result = DataSourceUtil.getDataSource(dataSourceProps.get("type").toString(), dataSourceProps);

            //*******适配druidDataSource,添加filter,否则不能实现sql,防火墙等监控功能!!!**************
            if (result instanceof DruidDataSource) {
                if (dataSourceProps.get(DRUID_FILTER_PREFIX) != null) {
                    ((DruidDataSource) result).setFilters(dataSourceProps.get(DRUID_FILTER_PREFIX).toString());
                }
            }
            DataSourcePropertiesSetterHolder.getDataSourcePropertiesSetterByType(dataSourceProps.get("type").toString()).ifPresent((dataSourcePropertiesSetter) -> {
                dataSourcePropertiesSetter.propertiesSet(environment, prefix, dataSourceName, result);
            });
            return result;
        }
    }

    private DataSource getJndiDataSource(String jndiName) throws NamingException {
        JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
        bean.setResourceRef(true);
        bean.setJndiName(jndiName);
        bean.setProxyInterface(DataSource.class);
        bean.afterPropertiesSet();
        return (DataSource) bean.getObject();
    }

    public MyShardingsphereConfig(SpringBootShardingRuleConfigurationProperties shardingRule, SpringBootMasterSlaveRuleConfigurationProperties masterSlaveRule, SpringBootEncryptRuleConfigurationProperties encryptRule, SpringBootShadowRuleConfigurationProperties shadowRule, SpringBootPropertiesConfigurationProperties props) {
        this.shardingRule = shardingRule;
        this.masterSlaveRule = masterSlaveRule;
        this.encryptRule = encryptRule;
        this.shadowRule = shadowRule;
        this.props = props;
    }
} 


  • SpringBootApplication添加注解@SpringBootApplication(exclude = {SpringBootConfiguration.class, DataSourceAutoConfiguration.class}),不然也有坑

你可能感兴趣的:(最近版本,基于sharding-jdbc,druid,mybatisplus,springboot的分库分表,读写分离和sql监控功能实现,简单易用)