我是白小白 发表于 2023-1-17 13:41

使用 Nacos 配置中心 后 项目的多数据源 配置

本帖最后由 我是白小白 于 2023-1-17 13:47 编辑

可配置 多个源
都需 配置 mapper-locations
https://attach.52pojie.cn//forum/202301/17/134132yt2j3thys1jj032t.png?l

# 数据源配置

platform:
datasource:
    #1
    pj:
      id: pj
      mapper-package: com.pj
      mapper-locations: classpath:com/pj/project4sp/*.xml
      primary: true
      pool-name: pj
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/pj?characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
      type: com.zaxxer.hikari.HikariDataSource
      maximumPoolSize: 15
      idleTimeout: 30000
      connectionTimeout: 60000
      validationTimeout: 3000
      loginTimeout: 5
      maxLifetime: 60000

#2
    pp:
      id: pp
      mapper-package: com.pp
      mapper-locations: classpath:com/pp/project4sp/*.xml
      primary: false
      pool-name: pp
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/pp?characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
      type: com.zaxxer.hikari.HikariDataSource
      maximumPoolSize: 15
      idleTimeout: 30000
      connectionTimeout: 60000
      validationTimeout: 3000
      loginTimeout: 5
      maxLifetime: 60000
























代码
@Configuration
@Import(DataSourceIntegrationRegistrar.class)
public class DataSourceIntegrationConfig {


}

import com.alibaba.cloud.nacos.client.NacosPropertySource;
import com.zaxxer.hikari.HikariDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.cloud.bootstrap.support.OriginTrackedCompositePropertySource;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.*;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;



public class DataSourceIntegrationRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, BeanFactoryAware {

    private static final Logger logger = LoggerFactory.getLogger(DataSourceIntegrationRegistrar.class);
    //OriginTrackedCompositePropertySource {name='bootstrapProperties', propertySources=}]}
    private static final String CONFIG_PREFIX = "platform.datasource.";

    private Environment env;

    private ConfigurableListableBeanFactory beanFactory;

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
      AbstractEnvironment aEnv = (AbstractEnvironment) env;
      String profile = aEnv.getProperty("spring.profiles.active");
      MutablePropertySources propertySources = aEnv.getPropertySources();
      Map<String, Object> configMap = new LinkedHashMap<>();
      propertySources.forEach(propertySource -> {

            if (propertySource instanceof MapPropertySource) {
                MapPropertySource mps = (MapPropertySource) propertySource;
                Set<String> keys = mps.getSource().keySet();
                for (String key : keys) {
                  if (key.startsWith(CONFIG_PREFIX)) {
                        configMap.put(key, mps.getProperty(key));
                  }
                }

            }else if (propertySource instanceof OriginTrackedCompositePropertySource) {
                  OriginTrackedCompositePropertySource otcps = (OriginTrackedCompositePropertySource) propertySource;
                  Collection<PropertySource<?>> propertySources1 = otcps.getPropertySources();
                  for (PropertySource<?> propertySource1 : propertySources1) {
                        if (propertySource1 instanceof CompositePropertySource) {
                            CompositePropertySource nps = (CompositePropertySource) propertySource1;
                            Collection<PropertySource<?>> propertySources2 = nps.getPropertySources();
                            for (PropertySource<?> propertySource2 : propertySources2) {
                              if (propertySource2 instanceof NacosPropertySource) {
                                    NacosPropertySource nacosPropertySource = (NacosPropertySource) propertySource2;
                                    Set<String> keys = nacosPropertySource.getSource().keySet();
                                    for (String key : keys) {
                                        if (key.startsWith(CONFIG_PREFIX)) {
                                          configMap.put(key, nacosPropertySource.getProperty(key));
                                        }
                                    }
                              }
                            }
                        }
                  }
                }

      });

      Map<String, String> dataSourceItems = new LinkedHashMap<>();
      for (String s : configMap.keySet()) {
            String[] d = StringUtils.tokenizeToStringArray(s, ".");
            String prefix = d;
            String id = (String) getProperty(prefix, "id", configMap);
            String env = (String) getProperty(prefix, "env", configMap);
            if (!StringUtils.isEmpty(env)) {
                if (env.contains(profile)) {
                  dataSourceItems.put(id, prefix);
                }
            } else {
                dataSourceItems.put(id, prefix);
            }
      }
      dataSourceItems.forEach((key, value) -> {
            logger.info("数据源ID为:{},载入配置: {}", key, CONFIG_PREFIX + value);
            String dataSourceName = getArtifactName(key, "DataSource");
            String sqlSessionFactoryName = getArtifactName(key, "SqlSessionFactory");
            String sqlSessionTemplateName = getArtifactName(key, "SqlSessionTemplate");
            String transactionManagerName = getArtifactName(key, "TransactionManager");
            String mapperScanName = getArtifactName(key, "MapperScan");
            if (!beanFactory.containsBeanDefinition(dataSourceName)) {
                BeanDefinition dataSourceBeanDefinition = getDataSourceBeanDefinition(dataSourceName, value, configMap);
                registry.registerBeanDefinition(dataSourceName, dataSourceBeanDefinition);
                logger.info("自动注入DataSource:{}", dataSourceName);
            }
            if (!beanFactory.containsBeanDefinition(sqlSessionFactoryName)) {
                BeanDefinition sqlSessionFactoryBeanDefinition = null;
                try {
                  sqlSessionFactoryBeanDefinition = getSqlSessionFactoryBeanDefinition(sqlSessionFactoryName, value, dataSourceName, configMap);
                } catch (IOException e) {
                  e.printStackTrace();
                  throw new IllegalArgumentException(e);
                }
                registry.registerBeanDefinition(sqlSessionFactoryName, sqlSessionFactoryBeanDefinition);
                logger.info("自动注入SqlSessionFactory:{}", sqlSessionFactoryName);
            }
            if (!beanFactory.containsBeanDefinition(sqlSessionTemplateName)) {
                registry.registerBeanDefinition(sqlSessionTemplateName, getSqlSessionTemplateBeanDefinition(sqlSessionFactoryName, value, configMap, sqlSessionFactoryName));
                logger.info("自动注入SqlSessionTemplate:{}", sqlSessionTemplateName);
            }
            if (!beanFactory.containsBeanDefinition(transactionManagerName)) {
                registry.registerBeanDefinition(transactionManagerName, getTransactionManagerBeanDefinition(transactionManagerName, value, configMap, dataSourceName));
                logger.info("自动注入TransactionManager:{}", transactionManagerName);
            }
            registry.registerBeanDefinition(mapperScanName, getMapperScannerConfigurer(value, configMap, sqlSessionTemplateName));
      });
    }

    /**
   * 获取数据源BeanDefinition
   */
    private BeanDefinition getDataSourceBeanDefinition(String name, String s, Map<String, Object> configMap) {
      String poolName = String.valueOf(getProperty(s, "pool-name", configMap));
      String username = String.valueOf(getProperty(s, "username", configMap));
      String password = String.valueOf(getProperty(s, "password", configMap));
      String driverClassName = (String) getProperty(s, "driver-class-name", configMap);
      String jdbcUrl = (String) getProperty(s, "jdbc-url", configMap);
      String type = (String) getProperty(s, "type", configMap);
      Integer maximumPoolSize = (Integer) getProperty(s, "maximumPoolSize", configMap);
      Integer prepStmtCacheSize = (Integer) getProperty(s, "prepStmtCacheSize", configMap);
      Integer prepStmtCacheSqlLimit = (Integer) getProperty(s, "prepStmtCacheSqlLimit", configMap);
      Integer idleTimeout = (Integer) getProperty(s, "idleTimeout", configMap);
      Integer connectionTimeout = (Integer) getProperty(s, "connectionTimeout", configMap);
      Integer validationTimeout = (Integer) getProperty(s, "validationTimeout", configMap);
      Integer loginTimeout = (Integer) getProperty(s, "loginTimeout", configMap);
      Integer maxLifetime = (Integer) getProperty(s, "maxLifetime", configMap);
      Boolean cachePrepStmts = (Boolean) getProperty(s, "cachePrepStmts", configMap);
      Boolean useServerPrepStmts = (Boolean) getProperty(s, "useServerPrepStmts", configMap);
      Boolean useLocalSessionState = (Boolean) getProperty(s, "useLocalSessionState", configMap);
      Boolean useLocalTransactionState = (Boolean) getProperty(s, "useLocalTransactionState", configMap);
      Boolean rewriteBatchedStatements = (Boolean) getProperty(s, "rewriteBatchedStatements", configMap);
      Boolean cacheResultSetMetadata = (Boolean) getProperty(s, "cacheResultSetMetadata", configMap);
      Boolean elideSetAutoCommits = (Boolean) getProperty(s, "elideSetAutoCommits", configMap);
      Boolean maintainTimeStats = (Boolean) getProperty(s, "maintainTimeStats", configMap);

      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(HikariDataSource.class);
      builder.addPropertyValue("poolName", poolName);
      builder.addPropertyValue("username", username);
      builder.addPropertyValue("password", password);
      builder.addPropertyValue("driverClassName", driverClassName);
      builder.addPropertyValue("jdbcUrl", jdbcUrl);
//      builder.addPropertyValue("type", type);
      builder.addPropertyValue("maximumPoolSize", maximumPoolSize);
//      builder.addPropertyValue("prepStmtCacheSize", prepStmtCacheSize);
//      builder.addPropertyValue("prepStmtCacheSqlLimit", prepStmtCacheSqlLimit);
      builder.addPropertyValue("idleTimeout", idleTimeout);
      builder.addPropertyValue("connectionTimeout", connectionTimeout);
      builder.addPropertyValue("validationTimeout", validationTimeout);
      builder.addPropertyValue("loginTimeout", loginTimeout);
      builder.addPropertyValue("maxLifetime", maxLifetime);
//      builder.addPropertyValue("cachePrepStmts", cachePrepStmts);
//      builder.addPropertyValue("useServerPrepStmts", useServerPrepStmts);
//      builder.addPropertyValue("useLocalSessionState", useLocalSessionState);
//      builder.addPropertyValue("useLocalTransactionState", useLocalTransactionState);
//      builder.addPropertyValue("rewriteBatchedStatements", rewriteBatchedStatements);
//      builder.addPropertyValue("cacheResultSetMetadata", cacheResultSetMetadata);
//      builder.addPropertyValue("elideSetAutoCommits", elideSetAutoCommits);
//      builder.addPropertyValue("maintainTimeStats", maintainTimeStats);
      return handlePrimary(name, builder, s, configMap);
    }

    /**
   * 获取 SqlSessionFactory Bean 定义
   */
    private BeanDefinition getSqlSessionFactoryBeanDefinition(String name, String s, String dataSourceName, Map<String, Object> configMap) throws IOException {
      String mapperLocations = (String) getProperty(s, "mapper-locations", configMap);
      if (StringUtils.isEmpty(mapperLocations)) {
            throw new IllegalArgumentException(s + " mapper-locations配置为空!");
      }
      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SqlSessionFactoryBean.class);
      PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
      Resource[] resources = pathMatchingResourcePatternResolver.getResources(mapperLocations);
      builder.addPropertyValue("mapperLocations", resources);
      builder.addPropertyReference("dataSource", dataSourceName);
      return handlePrimary(name, builder, s, configMap);
    }

    /**
   * 获取SqlSessionTemplate Bean 定义
   */
    private BeanDefinition getSqlSessionTemplateBeanDefinition(String name, String s, Map<String, Object> configMap, String sqlSessionFactoryName) {
      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SqlSessionTemplate.class);
      builder.addConstructorArgReference(sqlSessionFactoryName);
      return handlePrimary(name, builder, s, configMap);
    }

    /**
   * 获取TransactionManager Bean 定义
   */
    private BeanDefinition getTransactionManagerBeanDefinition(String name, String s, Map<String, Object> configMap, String dataSourceName) {
      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DataSourceTransactionManager.class);
      builder.addConstructorArgReference(dataSourceName);
      return handlePrimary(name, builder, s, configMap);
    }

    /**
   * 获取 Mapper扫描注册组件 Bean定义
   */
    private BeanDefinition getMapperScannerConfigurer(String s,
                                                      Map<String, Object> configMap,
                                                      String sqlSessionTemplateBeanName) {
      String mapperPackage = (String) getProperty(s, "mapper-package", configMap);
      if (StringUtils.isEmpty(mapperPackage)) {
            throw new IllegalArgumentException(s + " mapper-package 配置为空!");
      }
      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
      builder.addPropertyValue("processPropertyPlaceHolders", true);
      builder.addPropertyValue("sqlSessionTemplateBeanName", sqlSessionTemplateBeanName);
      builder.addPropertyValue("basePackage", mapperPackage);
      return builder.getBeanDefinition();
    }

    /**
   * 处理 是否Primary
   */
    private AbstractBeanDefinition handlePrimary(String name, BeanDefinitionBuilder builder, String prefix, Map<String, Object> configMap) {
      Boolean primary = (Boolean) getProperty(prefix, "primary", configMap);
      AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
      if (primary != null && primary) {
            beanDefinition.setPrimary(true);
            logger.info("Bean: {} 设置为Primary", name);
      }
      return beanDefinition;
    }

    @Override
    public void setEnvironment(Environment environment) {
      this.env = environment;
    }

    private String getArtifactName(String key, String artifact) {
      return key + artifact;
    }

    private Object getProperty(String prefix, String key, Map<String, Object> configMap) {
      String s = CONFIG_PREFIX + prefix + ".";
      return configMap.get(s + key);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
      this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
    }
}




郭大路2019 发表于 2023-1-17 14:40

事务有没有问题

我是白小白 发表于 2023-1-17 16:54

郭大路2019 发表于 2023-1-17 14:40
事务有没有问题

事务没问题

我是白小白 发表于 2023-1-17 16:55

郭大路2019 发表于 2023-1-17 14:40
事务有没有问题

@Transactional(value = "pjTransactionManager", rollbackFor = {RuntimeException.class, Exception.class})    id+TransactionManager

郭大路2019 发表于 2023-4-3 12:29

所以你是单个数据库实例单个 事务管理器 是吧 如果一个大事务里面包含A数据源和B数据源的事务 你是怎么做的?

郭大路2019 发表于 2023-4-3 12:31

多数据源好配置 但是多数据源统一事务管理不好搞
页: [1]
查看完整版本: 使用 Nacos 配置中心 后 项目的多数据源 配置