使用 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
事务有没有问题
事务没问题 郭大路2019 发表于 2023-1-17 14:40
事务有没有问题
@Transactional(value = "pjTransactionManager", rollbackFor = {RuntimeException.class, Exception.class}) id+TransactionManager 所以你是单个数据库实例单个 事务管理器 是吧 如果一个大事务里面包含A数据源和B数据源的事务 你是怎么做的? 多数据源好配置 但是多数据源统一事务管理不好搞
页:
[1]