Fork me on GitHub
时钟canvas

springboot+mybatis的多数据源配置

1.链接数据库yml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
spring:
  datasource:
    master:
      jdbc-url: jdbc:mysql://localhost:3306/dams?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
      username: root
      password: root   
      driver-class-name: com.mysql.jdbc.Driver
 
    slave1:
      jdbc-url: jdbc:mysql://localhost:3306/root?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver
 
    slave2:
      jdbc-url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver

  

2.数据源配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
 *  * 关于数据源配置,参考SpringBoot官方文档第79章《Data Access》  * 79. Data Access
 *  * 79.1 Configure a Custom DataSource  * 79.2 Configure Two DataSources 
 */
@Configuration
public class DataSourceConfig {
//将master数据源注入
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }
 
//将slave1注入
    @Bean
    @ConfigurationProperties("spring.datasource.slave1")
    public DataSource slave1DataSource() {
        return DataSourceBuilder.create().build();
    }
 
//将slave2注入
    @Bean
    @ConfigurationProperties("spring.datasource.slave2")
    public DataSource slave2DataSource() {
        return DataSourceBuilder.create().build();
    }
 
// 我们配置了4个数据源,1个master,2两个slave,1个路由数据源。前3个数据源都是为了生成第4个数据源,而且后续我们只用这最后一个路由数据源。
    @Bean
    public DataSource myRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
            @Qualifier("slave1DataSource") DataSource slave1DataSource,
            @Qualifier("slave2DataSource") DataSource slave2DataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DBTypeEnum.MASTER, masterDataSource);
        targetDataSources.put(DBTypeEnum.SLAVE1, slave1DataSource);
        targetDataSources.put(DBTypeEnum.SLAVE2, slave2DataSource);
        MyRoutingDataSource myRoutingDataSource = new MyRoutingDataSource();
        myRoutingDataSource.setDefaultTargetDataSource(masterDataSource);// 主库数据源
        myRoutingDataSource.setTargetDataSources(targetDataSources);// 路由数据源
        return myRoutingDataSource;
    }
 
}

  3.SqlSessionFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@EnableTransactionManagement
@Configuration
public class MyBatisConfig {
 
    @Resource(name = "myRoutingDataSource")
    private DataSource myRoutingDataSource;
//将数据源设置到SqlSessionFactory
    @Bean
    public SqlSessionFactory sqlSessionFactory( MybatisProperties mybatisProperties) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(myRoutingDataSource);
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        sqlSessionFactoryBean.setConfiguration(mybatisProperties.getConfiguration());
        return sqlSessionFactoryBean.getObject();
    }
//将数据源设置到事务平台管理器
    @Bean
    public PlatformTransactionManager platformTransactionManager() {
        return new DataSourceTransactionManager(myRoutingDataSource);
    }
}

  4.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public enum  DBTypeEnum {
    MASTER,SLAVE1,SLAVE2;
}
 
 
 
 
 
//定义注解用来强制访问主库
public @interface Master {
}
 
//数据库切换
public class DBContextHolder {
//定义变量副本
    private static final ThreadLocal<DBTypeEnum> contextHolder = new ThreadLocal<>();
//定义安全自增
    private static final AtomicInteger counter = new AtomicInteger(-1);
 
    public static void set(DBTypeEnum dbType) {
        contextHolder.set(dbType);
    }
 
    public static DBTypeEnum get() {
        return contextHolder.get();
    }
 
    public static void master() {
        set(DBTypeEnum.MASTER);
        System.out.println("切换到master");
    }
 
    public static void slave() {
        //  轮询切换从数据库
        int index = counter.getAndIncrement() % 2;
        if (counter.get() > 9999) {
            counter.set(-1);
        }
        if (index == 0) {
            set(DBTypeEnum.SLAVE1);
            System.out.println("切换到slave1");
        }else {
            set(DBTypeEnum.SLAVE2);
            System.out.println("切换到slave2");
        }
    }
 
}

  5.

1
2
3
4
5
6
7
8
9
public class MyRoutingDataSource extends AbstractRoutingDataSource {
    //根据路由来确定map中的sqlsessionFactory
    @Nullable
    @Override
    protected Object determineCurrentLookupKey() {
        return DBContextHolder.get();
    }
 
}

  6.注入多数据源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class DataSourceAop {
 
    @Pointcut("!@annotation(com.tl.base.datasource.annotation.Master) " +
            "&& (execution(* com.tl.base.domain..*.query*(..)) " +
            "|| execution(* com.tl.base.domain..*.get*(..)))")
    public void readPointcut() {
 
    }
 
    @Pointcut("@annotation(com.tl.base.datasource.annotation.Master) " +
            "|| execution(* com.tl.base.domain..*.insert*(..)) " +
            "|| execution(* com.tl.base.domain..*.add*(..)) " +
            "|| execution(* com.tl.base.domain..*.update*(..)) " +
            "|| execution(* com.tl.base.domain..*.edit*(..)) " +
            "|| execution(* com.tl.base.domain..*.delete*(..)) " +
            "|| execution(* com.tl.base.domain..*.remove*(..))")
    public void writePointcut() {
 
    }
 
    @Before("readPointcut()")
    public void read() {
        DBContextHolder.slave();
    }
 
    @Before("writePointcut()")
    public void write() {
        DBContextHolder.master();
    }

  

posted @   dragonKings  阅读(393)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
欢迎阅读『springboot+mybatis的多数据源配置』
     
点击右上角即可分享
微信分享提示