SpringBoot2.0+Mybatis+Druid搭建一个最简单的多数据源

多数据源系列

1、spring boot2.0 +Mybatis + druid搭建一个最简单的多数据源

利用Spring的AbstractRoutingDataSource做多数据源动态切换

使用Dynamic-Datasource-Spring-Boot-Starter实现多数据源及源码分析

简介

在大部分情况下,搭建单数据源就能够满足需求了,但是特殊情况下也需要使用多数据源,这里就写了一个demo搭建多数据源,注意这里没有使用AbstractRoutingDataSource 来实现动态切换

实操

文件结构,最好每个数据源的mapper对应每个目录,分开来做

88647446-9FFA-1F2B-138E-582D6B05E3F9.jpeg

先上pom,这里只截取了关键的依赖

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	......
	<dependencies>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
		<!-- druid -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.18</version>
		</dependency>
		<dependency>
			<groupId>com.ibm.db2.jcc</groupId>
			<artifactId>db2jcc</artifactId>
			<version>9.7</version>
		</dependency>
	</dependencies>

下面是springboot的主配置,application.yml

logging: #打印sql
  level:
    com.example.demo.mapper.db1: debug
    com.example.demo.mapper.db2: debug
spring:
  datasource: #数据源配置
    type: com.alibaba.druid.pool.DruidDataSource
    db1:
      type: com.alibaba.druid.pool.DruidDataSource
      driverClassName: com.ibm.db2.jcc.DB2Driver
      initialize: true #指定初始化数据源,是否用data.sql来初始化,默认: true
      name: db1
      # 本地开发环境配置db2
      url: jdbc:db2://10.101.167.28:56000/QCD
      username: db2
      password: 123456
    db2:
      type: com.alibaba.druid.pool.DruidDataSource
      driverClassName: com.ibm.db2.jcc.DB2Driver
      initialize: true #指定初始化数据源,是否用data.sql来初始化,默认: true
      name: db2
      # 本地开发环境配置db2
      url: jdbc:db2://10.101.167.28:56000/SAMPLE
      username: db2
      password: 123456

下面是DB1的配置

package com.example.demo.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
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 org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration
// 扫描mapper接口包路径
@MapperScan(basePackages = "com.example.demo.mapper.db1", sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class DB1DataSourceConfig {
    
    // 配置连接池,这里直接new一个Druid连接池,
    // 也可以new其他的连接池,比如spring boot默认的hikari连接池
    @Bean(name = "db1DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    @Primary
    public DataSource setDataSource() {
        return new DruidDataSource();
    }

    // 事务配置
    @Bean(name = "db1TransactionManager")
    @Primary
    public DataSourceTransactionManager setTransactionManager(@Qualifier("db1DataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(new DruidDataSource());
    }

    // 配置sessionFactory,这里的多数据源就是每个数据源对应一个sessionFactory
    // 下面getResources的就是mapper.xml文件
    @Bean(name = "db1SqlSessionFactory")
    @Primary
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/db1/*.xml"));
        return bean.getObject();
    }

    // 配置SqlSessionTemplate
    @Bean(name = "db1SqlSessionTemplate")
    @Primary
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

这里为每个数据源都配置了连接池和sessionFactory,然后需要注意的是这里使用的@ConfigurationProperties注解来自动读取配置到DruidDataSource中,当然也可以@Value读取配置,然后手工在DruidDataSource对象中把值一个个set进去。

上面的yml配置中驱动名称应该写为driverClassName,而不是driver-class-name,不然会报找不到driver错误。

@MapperScan中配置扫描该数据库的mapper接口文件,这就把不同数据库的sql分开了,这样写了之后在Application主入口文件就不需要再去@MapperScan了。

同理第二个配置文件也是类似的

@Configuration
@MapperScan(basePackages = "com.example.demo.mapper.db2", sqlSessionTemplateRef = "db2SqlSessionTemplate")
public class DB2DataSourceConfig {
    @Bean(name = "db2DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource setDataSource() {
        return new DruidDataSource();
    }

    @Bean(name = "db2TransactionManager")
    public DataSourceTransactionManager setTransactionManager(@Qualifier("db2DataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(new DruidDataSource());
    }

    @Bean(name = "db2SqlSessionFactory")
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("db2DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/db2/*.xml"));
        return bean.getObject();
    }

    @Bean(name = "db2SqlSessionTemplate")
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("db2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

service文件写了两个测试方法

这里需要注意的是,这里配置的Bean没有跟第一个配置一样加上@Primary,所以默认的

DataSourceTransactionManager是属于DB1的,如果要开启DB2(另一个数据库)事务,需要手工指定一下这个manager,不然用的都是第一个db的事务管理器,导致事务不生效

在调用到这个数据源的方法上加上这个即可

@Transactional(transactionManager = "db2TransactionManager")
@Service
public class TestService {

    @Autowired
    private TestDB1Mapper testDB1Mapper;

    @Autowired
    private TestDB2Mapper testDB2Mapper;

    public List<Map<String, Object>> testDB1() {
        return testDB1Mapper.selectDB1();
    }

    public List<Map<String, Object>> testDB2() {
        return testDB2Mapper.selectDB2();
    }
}

运行结果

275FC26C-1C10-B710-6B1A-12A898BCEBF8.jpeg

发现它初始化了两个连接池对象,然后开始执行sql语句。

这里初始化连接池还是有点慢,是个比较重量级的操作,如果需要连接许多数据库,比如根据某张表的配置信息,去连接某某数据库,这个时候采用动态数据源的方式比较好,这个在后面两篇博客会介绍到。

收藏 (0)
评论列表
正在载入评论列表...
我是有底线的
为您推荐
    暂时没有数据