SpringBoot + MyBatis使用多数据源

mybatis
#1

SpringBoot + MyBatis使用多数据源

有时候我们需要在一个项目里面集成一个或者多个数据源。

实现的思想

  • 使用mybatis持久层框架
  • mybatis的运行需要依赖于几个组件
    • DataSource 数据源
    • DataSourceTransactionManager 事务管理器
    • SqlSessionFactory SqlSession工厂,负责创建SqlSession
    • SqlSessionTemplate SqlSession,负责执行crud
  • 多数据源,就是使用多个数据源,多个事务管理器,多个SqlSession工厂,就有不同的SqlSession

Maven

使用Druid作为数据源

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.0.0</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.14</version>
		</dependency>
	</dependencies>

application.yml

配置多个数据源,这里仅仅配置了基本必须的属性

logging:
  level:
    root: debug

datasource:
  1:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot1?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&serverTimezone=GMT%2b8
    username: root
    password: root
  
  2:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&serverTimezone=GMT%2b8
    username: root
    password: root

多个数据源的@Configuration 配置

第一个数据源以及持久层需要的组件

package io.springboot.multidatasource.configuration;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
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.jdbc.datasource.DataSourceTransactionManager;

import com.alibaba.druid.pool.DruidDataSource;
@Configuration
public class DataSourceConfiguration1 {
	
	@Bean(name = "dataSource1")
	@Primary
	@ConfigurationProperties(prefix = "datasource.1")
	public DataSource dataSource() {
		return new DruidDataSource();
	}
	
	@Bean(name = "dataSourceTransactionManager1")
	@Primary
	public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dataSource1")DataSource dataSource) {
		return new DataSourceTransactionManager(dataSource);
	}
	
	@Bean(name = "sqlSessionFactory1")
	@Primary
	public SqlSessionFactory sessionFactory(@Qualifier("dataSource1")DataSource dataSource) throws Exception {
		SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
		sessionFactoryBean.setDataSource(dataSource);
		return sessionFactoryBean.getObject();
	}
	
	@Bean("sqlSessionTemplate1")
	@Primary
	public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) {
		return new SqlSessionTemplate(sqlSessionFactory);
	}
}

第二个数据源以及持久层需要的组件

package io.springboot.multidatasource.configuration;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
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.jdbc.datasource.DataSourceTransactionManager;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
public class DataSourceConfiguration2 {
	@Bean(name = "dataSource2")
	@ConfigurationProperties(prefix = "datasource.2")
	public DataSource dataSource() {
		return new DruidDataSource();
	}
	
	@Bean(name = "dataSourceTransactionManager2")
	public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dataSource2")DataSource dataSource) {
		return new DataSourceTransactionManager(dataSource);
	}
	
	@Bean(name = "sqlSessionFactory2")
	public SqlSessionFactory sessionFactory(@Qualifier("dataSource2")DataSource dataSource) throws Exception {
		SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
		sessionFactoryBean.setDataSource(dataSource);
		return sessionFactoryBean.getObject();
	}
	
	@Bean("sqlSessionTemplate2")
	public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) {
		return new SqlSessionTemplate(sqlSessionFactory);
	}
}

可以看到,配置1中的bean,比配置2中的bean多了一个 @Primary 注解。
当其他的组件通过@Autowired等方式注入一个类的时候。而IOC中有多个该的实现。那么标注了@Primary 注解的Bean会优先注入。详细可以参阅官方文档

https://docs.spring.io/spring/docs/5.1.5.RELEASE/spring-framework-reference/core.html#beans-autowired-annotation-primary

Main

package io.springboot.multidatasource;


import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.annotation.MapperScans;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScans(value = {
	@MapperScan(basePackages = "io.springboot.multidatasource.mapper1",
			sqlSessionFactoryRef = "sqlSessionFactory1",sqlSessionTemplateRef = "sqlSessionTemplate1"),
	
	@MapperScan(basePackages = "io.springboot.multidatasource.mapper2",
			sqlSessionFactoryRef = "sqlSessionFactory2",sqlSessionTemplateRef = "sqlSessionTemplate2"),
})
public class MultidatasourceApplication {
	public static void main(String[] args) {
		SpringApplication.run(MultidatasourceApplication.class, args);
	}
}

重点在于 @MapperScan注解。该注解会去扫描指定包下的接口。并且动态的生成实现类。
通过 sqlSessionFactoryRef 和 sqlSessionTemplateRef 指定它们生成代理对象时。使用的SqlSessionFactory 和 SqlSession。(值就是定义在了IOC中的bean名称)。

源码

0 Likes