java使用druid配置多数据源(获取数据库源) AbstractRoutingDataSource

书接上文使用nacos配置多数据源(druid)AbstractRoutingDataSource

根据配置文件切换数据源讲了,但对于某些特殊场景可能依旧有点问题,比如通过数据源生成代码,导出文档什么的,可能会有多个数据源,而且这些数据源肯定是不会走nacos的所以就有了本篇文章,写的很糙请谅解,可以自己优化

修改了多数据源bean的配置类

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.db.Db;
import com.alibaba.druid.pool.DruidDataSource;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;

import java.util.*;
import java.util.stream.Collectors;

import static com.joolun.cloud.salaryother.api.config.DynamicDataSourceSwitcher.MATER;
import static com.joolun.cloud.salaryother.api.config.DynamicDataSourceSwitcher.SLAVE1;

/**
 * 多数据源bean的配置类
 *
 * @author ycg
 */
@Configuration
public class MultipleDataSourceConfig {
    //    private static final Log logger = LogFactory.getLog(JdbcUtils.class);
    private final StringEncryptor stringEncryptor;

    public MultipleDataSourceConfig(StringEncryptor stringEncryptor) {
        this.stringEncryptor = stringEncryptor;
    }

    @Bean(MATER)
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource createMasterDataSource() {
        return new DruidDataSource();
    }

    @Bean(SLAVE1)
    @ConfigurationProperties(prefix = "spring.datasource.slave1")
    public DataSource createSlave1DataSource() {
        return new DruidDataSource();
    }


    /**
     * 设置动态数据源,通过@Primary 来确定主DataSource
     *
     * @return
     */
    @Bean
    @Primary
    @SneakyThrows
    public DataSource createDynamicDataSource(@Qualifier(MATER) DataSource master, @Qualifier(SLAVE1) DataSource slave1) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        //设置默认数据源
        dynamicDataSource.setDefaultTargetDataSource(master);
        //配置多数据源
        Map<Object, Object> druidDataSourceMap = new HashMap<>(16);
        try {
            druidDataSourceMap = Db.use(master)
                    .query("select id,name,url,username,password,driver_class_name from  datasource_data where del_flag = 0", DatasourceData.class).parallelStream()
                    .filter(ObjectUtil::isNotNull).peek(n -> n.setPassword(stringEncryptor.decrypt(n.getPassword())))
                    .map(n -> {
                        DruidDataSource druidDataSource = new DruidDataSource();
                        BeanUtils.copyProperties(master, druidDataSource);
                        if (StringUtils.isNotBlank(n.getDriverClassName())) {
                            druidDataSource.setDriverClassName(n.getDriverClassName());
                        }
                        druidDataSource.setName(n.getName());
                        druidDataSource.setUrl(n.getUrl());
                        druidDataSource.setUsername(n.getUsername());
                        druidDataSource.setPassword(n.getPassword());
                        return druidDataSource;
                    }).collect(Collectors.toMap(DruidDataSource::getName, n -> n, (v1, v2) -> v2));
        } finally {
            druidDataSourceMap.put("master", master);
            druidDataSourceMap.put("slave1", slave1);
        }
        
        dynamicDataSource.setTargetDataSources(druidDataSourceMap);
        return dynamicDataSource;
    }


}

修改

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;



import static com.joolun.cloud.salaryother.api.config.DynamicDataSourceSwitcher.MATER;

/**
 * 多数据源
 *
 * @author xiyu
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);

    @Override
    protected Object determineCurrentLookupKey() {
        String dataSource = DynamicDataSourceSwitcher.getDataSource();
        if (StringUtils.isBlank(dataSource)) return MATER;
        if (getResolvedDataSources().containsKey(dataSource)) {
            return dataSource;
        }
        logger.info("数据源中不包含切换源----------使用默认数据源 {}", MATER);
        return MATER;
    }


}
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 创建aop切面
 *
 * @author xiyu
 */
@Aspect
@Component
@Order(1)
public class DynamicDataSourceAspect {


    /**
     * 切入点只对@Service注解的类上的@DataSource方法生效
     *
     * @param myDataSource
     */
    @Pointcut(value = "@within(org.springframework.stereotype.Service) && @annotation(myDataSource)")
    public void dynamicDataSourcePointCut(MyDataSource myDataSource) {
    }

    @Before(value = "dynamicDataSourcePointCut(myDataSource)", argNames = "myDataSource")
    public void switchDataSource(MyDataSource myDataSource) {
        DynamicDataSourceSwitcher.setDataSource(myDataSource.value());
    }

    /**
     * 切点执行完后 切换成主数据库
     *
     * @param myDataSource
     */
    @After(value = "dynamicDataSourcePointCut(myDataSource)", argNames = "myDataSource")
    public void after(MyDataSource myDataSource) {
        DynamicDataSourceSwitcher.cleanDataSource();
    }
}
/**
 * 操作数据源
 *
 * @author xiyu
 */
public class DynamicDataSourceSwitcher {

    public static final String MATER = "master";
    public static final String SLAVE1 = "slave1";

    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDataSource(String name) {
            CONTEXT_HOLDER.set(name);
    }

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

    public static void cleanDataSource() {
        CONTEXT_HOLDER.remove();
    }

}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static com.joolun.cloud.salaryother.api.config.DynamicDataSourceSwitcher.MATER;

/**
 * 自定义的数据源的注解
 *
 * @author xiyu
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({
        ElementType.METHOD
})
public @interface MyDataSource {
    String value() default MATER;
}

以下都是老代码懒得改了
增加对数据库操作 service层

private final StringEncryptor stringEncryptor;
	@Qualifier("createDynamicDataSource")
	private  DynamicDataSource dataSource;

	/**
	 * 保存数据源并且加密
	 *
	 * @param datasourceData
	 * @return
	 */
	@Override
	public Boolean saveSysDatasource(DatasourceData datasourceData) {

		//校验数据源配置是否能链接
		try {
			DriverManager.getConnection(datasourceData.getUrl(), datasourceData.getUsername(), datasourceData.getPassword());
		}catch (SQLException e){
			log.error(e.getMessage(), e);
			throw new RuntimeException("连接失败,请检查配置信息:" + e.getMessage());
		}

		//添加动态数据源
//		DynamicDataSource dynamicDataSource = new DynamicDataSource();
		Map<Object, Object> map = new HashMap<>(16);
		DruidDataSource druidDataSource = new DruidDataSource();
		druidDataSource.setName(datasourceData.getName());
		druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		if(StringUtils.isNotBlank(datasourceData.getDriverClassName())){
			druidDataSource.setDriverClassName(datasourceData.getDriverClassName());
		}
		druidDataSource.setUrl(datasourceData.getUrl());
		druidDataSource.setUsername(datasourceData.getUsername());
		druidDataSource.setPassword(datasourceData.getPassword());
		map.put(datasourceData.getName(), druidDataSource);
		dataSource.setTargetDataSources(map);
		dataSource.afterPropertiesSet();
		datasourceData.setPassword(stringEncryptor.encrypt(datasourceData.getPassword()));
		datasourceData.setTenantId(null);
		this.baseMapper.insert(datasourceData);
		return Boolean.TRUE;
	}

	/**
	 * 更新数据源
	 *
	 * @param datasourceData
	 * @return
	 */
	@Override
	public Boolean updateSysDatasource(DatasourceData datasourceData) {
		//校验数据源配置是否能链接
		try {
			DriverManager.getConnection(datasourceData.getUrl(),datasourceData.getUsername(),datasourceData.getPassword());
		}catch (SQLException e){
			log.error(e.getMessage(), e);
			throw new RuntimeException("连接失败,请检查配置信息:" + e.getMessage());
		}
		//先删除动态数据源
		DynamicDataSourceSwitcher.cleanDataSource();
		Map<Object, DataSource> resolvedDataSources = dataSource.getResolvedDataSources();
		if(resolvedDataSources.containsKey(datasourceData.getName())){
			resolvedDataSources.remove(datasourceData.getName());
		}
		//再添加动态数据源
//		DynamicDataSource dynamicDataSource = new DynamicDataSource();
		Map<Object, Object> map = new HashMap<>(16);
		DruidDataSource druidDataSource = new DruidDataSource();
		druidDataSource.setName(datasourceData.getName());
		druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		if(StringUtils.isNotBlank(datasourceData.getDriverClassName())){
			druidDataSource.setDriverClassName(datasourceData.getDriverClassName());
		}
		druidDataSource.setUrl(datasourceData.getUrl());
		druidDataSource.setUsername(datasourceData.getUsername());
		druidDataSource.setPassword(datasourceData.getPassword());
		map.put(datasourceData.getName(), druidDataSource);
		dataSource.setTargetDataSources(map);
		dataSource.afterPropertiesSet();
		if (StringUtils.isNotBlank(datasourceData.getPassword())) {
			datasourceData.setPassword(stringEncryptor.encrypt(datasourceData.getPassword()));
		}
		this.baseMapper.updateById(datasourceData);
		return Boolean.TRUE;
	}
@Data
@ApiModel(value="数据源表")
@TableName("datasource_data")
@EqualsAndHashCode(callSuper = true)
public class DatasourceData extends Model<DatasourceData> {
	private static final long serialVersionUID = 1L;

	/**
	 * 主键
	 */
	@ApiModelProperty(value = "主键")
	@TableId(type = IdType.ASSIGN_ID)
	private String id;
	/**
	 * 名称
	 */
	@ApiModelProperty(value = "名称")
	@NotBlank(message = "数据源名称不能为空")
	private String name;
	/**
	 * jdbcurl
	 */
	@ApiModelProperty(value = "jdbcurl")
	@NotBlank(message = "jdbcurl不能为空")
	private String url;
	/**
	 * 用户名
	 */
	@ApiModelProperty(value = "用户名")
	@NotBlank(message = "用户名不能为空")
	private String username;
	/**
	 * 密码
	 */
	@ApiModelProperty(value = "密码")
	@NotBlank(message = "密码不能为空")
	private String password;
	/**
	 * 驱动
	 */
	@ApiModelProperty(value = "驱动")
	@NotBlank(message = "驱动不能为空")
	private String driverClassName;
	/**
	 * 创建时间
	 */
	@ApiModelProperty(value = "创建时间")
	private LocalDateTime createTime;
	/**
	 * 更新时间
	 */
	@ApiModelProperty(value = "更新时间")
	private LocalDateTime updateTime;
	/**
	 * 删除标记
	 */
	@ApiModelProperty(value = "删除标记")
	private String delFlag;
	/**
	 * 租户ID
	 */
	@ApiModelProperty(value = "租户ID")
	private String tenantId;

}

获取数据库表名列表和表字段

<select id="queryList" resultType="map">
		select table_name tableName, engine, table_comment tableComment, create_time createTime from information_schema.tables
			where table_schema = (select database())
		<if test="tableName != null and tableName.trim() != ''">
			and table_name like concat('%', #{tableName}, '%')
		</if>
		order by create_time desc
	</select>

	<select id="queryTable" resultType="map">
		select table_name tableName, engine, table_comment tableComment, create_time createTime from information_schema.tables
			where table_schema = (select database()) and table_name = #{tableName}
	</select>

	<select id="queryColumns" resultType="map">
		select column_name columnName, data_type dataType, column_comment columnComment, column_key columnKey, extra, character_maximum_length, is_nullable from information_schema.columns
 			where table_name = #{tableName} and table_schema = (select database()) order by ordinal_position
	</select>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
您可以使用Druid配置多数据源来实现在一个应用程序连接多个数据库。以下是一种常见的配置方式: 1. 在application.properties(或application.yml)文件添加以下配置: ```yaml # 第一个数据源 spring.datasource.url=jdbc:mysql://localhost:3306/db1 spring.datasource.username=db1_user spring.datasource.password=db1_password spring.datasource.driver-class-name=com.mysql.jdbc.Driver # 第二个数据源 spring.datasource.secondary.url=jdbc:mysql://localhost:3306/db2 spring.datasource.secondary.username=db2_user spring.datasource.secondary.password=db2_password spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver ``` 2. 创建两个数据源配置类,分别对应第一个和第二个数据源: ```java @Configuration @ConfigurationProperties(prefix = "spring.datasource") public class DataSourceConfig { private String url; private String username; private String password; private String driverClassName; // Getter and Setter methods } @Configuration @ConfigurationProperties(prefix = "spring.datasource.secondary") public class SecondaryDataSourceConfig { private String url; private String username; private String password; private String driverClassName; // Getter and Setter methods } ``` 3. 创建Druid数据源配置类: ```java @Configuration public class DruidConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource(DataSourceConfig dataSourceConfig) { DruidDataSource druidDataSource = new DruidDataSource(); // 设置数据源属性 druidDataSource.setUrl(dataSourceConfig.getUrl()); druidDataSource.setUsername(dataSourceConfig.getUsername()); druidDataSource.setPassword(dataSourceConfig.getPassword()); druidDataSource.setDriverClassName(dataSourceConfig.getDriverClassName()); // 其他配置... return druidDataSource; } @Bean @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource(SecondaryDataSourceConfig secondaryDataSourceConfig) { DruidDataSource druidDataSource = new DruidDataSource(); // 设置数据源属性 druidDataSource.setUrl(secondaryDataSourceConfig.getUrl()); druidDataSource.setUsername(secondaryDataSourceConfig.getUsername()); druidDataSource.setPassword(secondaryDataSourceConfig.getPassword()); druidDataSource.setDriverClassName(secondaryDataSourceConfig.getDriverClassName()); // 其他配置... return druidDataSource; } } ``` 4. 在需要使用不同数据源的地方,使用`@Qualifier`注解指定要使用数据源: ```java @Service public class MyService { @Autowired @Qualifier("dataSource") private DataSource dataSource; @Autowired @Qualifier("secondaryDataSource") private DataSource secondaryDataSource; // 使用数据源进行操作... } ``` 这样就可以在应用程序使用多个数据源了。请根据您的具体需求进行配置和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值