动态数据源配置

  • 操作步骤:
  • 一、数据源配置配置方式:
  • 二、动态数据源相关类
    • 1. 枚举类定义如下:
    • 2. 重写查找当前数据源的方法:
    • 3. 用ThreadLocal变量存储查询数据源的字符串:
    • 4. 用动态数据源替换掉普通的数据源
  • 二、测试结果。
    • 1. Mapper类
    • 2.TestMapper
  • 二、重点来了!!

操作步骤:

提示:SpringBoot工程这里可以在properties文件里直接进行配置

一、数据源配置配置方式:

#数据源配置一(默认数据源)

spring.datasource.test1.jdbc-url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=falsespring.datasource.test1.username=rootspring.datasource.test1.password=123456spring.datasource.test1.driver-class-name=com.mysql.jdbc.Driver

#数据源配置二

spring.datasource.test2.jdbc-url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=UTF-8&useSSL=falsespring.datasource.test2.username=rootspring.datasource.test2.password=123456spring.datasource.test2.driver-class-name=com.mysql.jdbc.Driver

二、动态数据源相关类

我们用枚举类来定义数据源

1. 枚举类定义如下:

代码如下(示例):

public enum DBEnum { test1("test1Datasource"), test2("test2Datasource"); private String value; DBEnum(String value) { this.value = value; } public String getValue() { return value; }}

2. 重写查找当前数据源的方法:

/** * 提供动态数据源的类 */public class DynamicDataSource extends AbstractRoutingDataSource{ /*** 覆盖AbstractRoutingDataSource查找当前数据源id的方法。**/ @Override protected Object determineCurrentLookupKey() {return DbContextHolder.getDbType(); }}

3. 用ThreadLocal变量存储查询数据源的字符串:

/** * 数据源的id绑定当前线程 */public class DbContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();/*** 设置数据源(数据源字符串名称)*/ public static void setDbType(DBEnum dbEnum) { contextHolder.set(dbEnum.getValue()); } /*** 取得当前数据源(数据源字符串名称)*/ public static String getDbType() { return contextHolder.get(); } /*** 清除上下文数据源*/ public static void clearDbType() { contextHolder.remove(); }}

4. 用动态数据源替换掉普通的数据源

@Configurationpublic class DbConfig {@Bean(name = "test1Datasource")@ConfigurationProperties(prefix = "spring.datasource.test1") //可以将配置文件的属性除去前缀后,赋值到bean中public DataSource test1Datasource(){DataSource dataSource = DataSourceBuilder.create().build();return dataSource;} @Bean(name = "test2Datasource")@ConfigurationProperties(prefix = "spring.datasource.test2")public DataSource test2Datasource(){ DataSource dataSource = DataSourceBuilder.create().build();return dataSource;}/** * 动态数据源 * @return */@Bean(name = "dynamicDataSource")@Primary/**设置成Primary时,注入时如果是按类型注入的话,会优先!而实际上[自动的配置]里面就是按DataSource类型注入的*/public DataSource dataSource() {DynamicDataSource dynamicDataSource = new DynamicDataSource(); // 配置多数据源 Map<Object, Object> dsMap = new HashMap<>(2);dsMap.put("test1Datasource", test1Datasource());dsMap.put("test2Datasource", test2Datasource());dynamicDataSource.setTargetDataSources(dsMap);// 默认数据源 dynamicDataSource.setDefaultTargetDataSource(test1Datasource());return dynamicDataSource;}}/* * 原来用xml配置动态数据源的形式 */ 

二、测试结果。

1. Mapper类

@Mapperpublic interface UserMapper {@Insert("insert into user (id,name) values (#{id},#{name}) ") public void insert(@Param("id")Integer id ,@Param("name")String name);@Select("select * from user") @ResultType(User.class) public List<User> selectList();@Update("update user set name = #{name} where id = #{id}") public void updateByKey(User user);@Delete("delete from userwhere id = #{id}") public void deleteById(Integer id);}

2.TestMapper

提示:这里使用ThreadLocal记得要释放内存,尤其是利用线程池的时候,不然容易诱发内存泄露

@RunWith(SpringJUnit4ClassRunner.class)@SpringBootTest(classes= Application.class)public class TestMapper { @Autowired private UserMapper userMapper; @Test public void test1(){userMapper.insert(1, "张三");DbContextHolder.setDbType(DBEnum.test2);userMapper.insert(1, "张三");DbContextHolder.clearDbType(); }}

二、重点来了!!

按照以上的步骤测试会出现一下循环依赖报错的问题:

出现问题的原因是跟数据源自动配置冲突了,我们可以排除掉数据源自动配置的类就好了