springboot 多数据源,支持事物管理

开始前的准备

添加依赖

<!--aop支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<!--配置 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		<!-- 数据库连接池 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>${druid.version}</version>
		</dependency>
		<!-- mybatis -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>${mybatis.version}</version>
		</dependency>

多数据源配置文件

用于存放数据库的配置信息

public class DataSourceContainer {
	private String username;
	private String password;
	private String url;
	private String driverClassName;
	/**
	 * @info 记录数据源的名称,为了切换数据源做准备
	 */
	private String name;
	/**
	 * @info 描述数据库
	 */
	private String describe;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getDriverClassName() {
		return driverClassName;
	}

	public void setDriverClassName(String driverClassName) {
		this.driverClassName = driverClassName;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDescribe() {
		return describe;
	}

	public void setDescribe(String describe) {
		this.describe = describe;
	}

	@Override
	public String toString() {
		return "DataSourceContainer [username=" + username + ", password=" + password + ", url=" + url
				+ ", driverClassName=" + driverClassName + ", name=" + name + ", describe=" + describe + "]";
	}

}

可以在yml或者properties中使用提示配置

  @Configuration
@ConfigurationProperties(prefix = DataSourceList.prefix)
public class DataSourceList {
	protected static final String prefix = "project.data-source-list";
	private List<DataSourceContainer> dataSourceList;

	public List<DataSourceContainer> getDataSourceList() {
		return dataSourceList;
	}

	public void setDataSourceList(List<DataSourceContainer> dataSourceList) {
		this.dataSourceList = dataSourceList;
	}

	@Override
	public String toString() {
		return "DataSourceList [dataSourceList=" + dataSourceList + "]";
	}


}

yml 配置

# 项目多数据源配置
project:
  data-source-list:
    data-source-list:
    -
      username: 
      password: 
      url: 
      describe: 
      name: 
      driver-class-name:  
       -
      username: 
      password: 
      url: 
      describe: 
      name: 
      driver-class-name:

创建可根据key名称切换的动态数据源

public class DynamicDataSource extends AbstractRoutingDataSource {
	public static final Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);

	@Override
	protected Object determineCurrentLookupKey() {
		DataSourceEnum key = DataSourceContextHolder.get();
		logger.info("当前数据源{}", key == null ? DataSourceEnum.defaultDataSource : key);
		return key;
	}
}

核心:动态数据源配置,将所有数据源创建出来,并交给spring负责管理

@Configuration
public class DynamicDataSourceConfiguration {
	private static final Logger LOGGER = LoggerFactory.getLogger(DynamicDataSourceConfiguration.class);
	// 数据源名称集合
	private static List<String> dataSourceNamelist = new ArrayList<>();
	// 其他数据源集合 key - 名称, value 。。。。
	private static Map<Object, Object> targetDataSourceMap = new HashMap<>();

	private static void notTrue(boolean bo, String message) {
		if (bo == false) {
			throw new IllegalArgumentException(message);
		}
	}

	public DynamicDataSourceConfiguration(@Autowired DataSourceList dataSourceList) {
		List<DataSourceContainer> daList = dataSourceList.getDataSourceList();
		Assert.notNull(daList, "请配置更多的数据源");
		if (LOGGER.isInfoEnabled()) {
			LOGGER.info("项目中数据源包括{}", dataSourceList);
		}
		DataSourceEnum[] values = DataSourceEnum.values();
		for (DataSourceEnum val : values) {
			dataSourceNamelist.add(val.name());
		}
		for (DataSourceContainer dc : daList) {
			String username = dc.getUsername();
			String password = dc.getPassword();
			String url = dc.getUrl();
			String name = dc.getName();
			notTrue(dataSourceNamelist.contains(name),
					"请确定你的数据源实例名称和" + DataSourceEnum.class.getName() + "类中任意一个元素匹配。");
			DruidDataSource build = DruidDataSourceBuilder.create().build();
			build.setUsername(username);
			build.setPassword(password);
			build.setUrl(url);
			targetDataSourceMap.put(DataSourceEnum.valueOf(name), build);
		}
	}

	/**
	 * @info 默认数据库
	 * @return
	 */
	@Bean
	@ConfigurationProperties(prefix = "spring.datasource")
	public DataSource defaultDataSource() {
		if (LOGGER.isInfoEnabled()) {
			LOGGER.info("在{}创建了默认数据源", DateUtil.getCurrentTimeStr(DateConstant.DEFAULT));
		}
		return DruidDataSourceBuilder.create().build();
	}

	@Bean
	public DataSource dynamicDataSource() {
		DynamicDataSource dataSource = new DynamicDataSource();
		dataSource.setDefaultTargetDataSource(defaultDataSource());
		targetDataSourceMap.remove(DataSourceEnum.defaultDataSource);
		targetDataSourceMap.put(DataSourceEnum.defaultDataSource, defaultDataSource());
		dataSource.setTargetDataSources(targetDataSourceMap);
		return dataSource;
	}

	@Bean
	public SqlSessionFactory sqlSessionFactory() throws Exception {
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dynamicDataSource());
		// 设置别名
		sqlSessionFactoryBean.setTypeAliasesPackage("com.sinosoft.model.dbmodel");
		// 此处设置为了解决找不到mapper文件的问题
		sqlSessionFactoryBean
				.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
		return sqlSessionFactoryBean.getObject();
	}

	@Bean
	public SqlSessionTemplate sqlSessionTemplate() throws Exception {
		return new SqlSessionTemplate(sqlSessionFactory());
	}
	
	@Bean
	public JdbcTemplate jdbcTemplate() {
		return new JdbcTemplate(dynamicDataSource());
	}

	/**
	 * @info 事务管理,多个数据库都可以使用
	 * @return 事务管理实例
	 */
	@Bean
	public PlatformTransactionManager platformTransactionManager() {
		return new DataSourceTransactionManager(dynamicDataSource());
	}
}

如何使用

根据我们继承AbstractRoutingDataSource类重写determineCurrentLookupKey方法的返回值的类型 进行key切换

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值