Spring Boot2.x-10 基于Spring Boot 2.1.2 + Mybatis 2.0.0实现多数据源,支持事务

版权声明:【show me the code ,change the world】 https://blog.csdn.net/yangshangwei/article/details/86755745

概述

Spring Boot2.x-09 基于Spring Boot + Mybatis使用自定义注解实现数据库切换 通过自定义注解实现了数据库的切库。多数据源的支持我们通过这篇博文来梳理。

单个数据源 见 Spring Boot2.x-07Spring Boot2.1.2整合Mybatis


思路

让不同的数据源绑定不同的mybatis配置,再细化一点就是让不同的数据源扫描不同的包,让不同包下的mapper连接不同的数据源去处理业务逻辑。

多说一句,对于跨库的多表操作,这种整合是支持不了的


步骤

我们基于 Spring Boot2.x-09 基于Spring Boot + Mybatis使用自定义注解实现数据库切换 来改造下,让其支持多数据源。

在这里插入图片描述


Step1 多数据源配置文件applicaiton.yml

自定义前缀,在标注了@Configuration的配置类中通过prefix 将数据源关联起来。 这里的配置类为DatasourceConfig。

# datasource  db1   前缀为自定义的datasource-db1
spring:
  datasource-db1:
    driver-class-name: com.mysql.cj.jdbc.Driver # JDBC连接Mysql6以上com.mysql.cj.jdbc.Driver (服务端为Mysql8)
    url: jdbc:mysql://localhost:3306/db1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: root


# datasource db2  前缀为自定义的datasource-db2
  datasource-db2: 
    driver-class-name: com.mysql.cj.jdbc.Driver # JDBC连接Mysql6以上com.mysql.cj.jdbc.Driver  (服务端为Mysql8)
    url: jdbc:mysql://localhost:3306/db2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: root

# mybatis 
mybatis_db1: 
  # 映射文件的路径 , 这个切换数据源的场景下不能配置 * 通配符,有多个 逗号隔开,继续跟 classpath:mapper_db1/XXX
  # 在MybatisConfig.java#sqlSessionFactoryBean方法中通过sqlSessionFactoryBean设置classpath:mapper_db1/*.xml ,不然每次都要改这个地方,不好维护。
  #  mapper-locations: classpath:mapper_db1/*.xml  
  
  # 类型别名包配置,只能指定具体的包,多个配置可以使用英文逗号隔开
  # 也可以通过sqlSessionFactoryBean.setTypeAliasesPackage("com.artisan.domain.db1")
  type-aliases-package: com.artisan.domain.db1
  
  
  # Mybatis SQL语句控制台打印
  configuration: 
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      
 # mybatis 
mybatis_db2: 
  # 映射文件的路径 , 这个切换数据源的场景下不能配置 * 通配符,有多个 逗号隔开,继续跟 classpath:mapper/XXX
  # 在MybatisDB2Config.java#sqlSessionFactoryBean方法中通过sqlSessionFactoryBean设置classpath:mapper_db2/*.xml ,不然每次都要改这个地方,不好维护。
  #mapper-locations: classpath:mapper_db2/*.xml  
  
  
  # 类型别名包配置,只能指定具体的包,多个配置可以使用英文逗号隔开
  type-aliases-package: com.artisan.domain.db2
  
  
  # Mybatis SQL语句控制台打印
  configuration: 
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

Step2 初始化多个数据源

这里同时也初始化了JdbcTemplate和事务管理,当然了对这个例子是可选操作。 主要是不同DataSource的初始化

多个数据源,操作JdbcTemplate和Transaction,需要指定使用哪个数据源,否则Spring根据type找到多个bean,不知道注入哪个。 【使用@Primary或者@Qualifier都可以】

package com.artisan.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
public class DatasourceConfig {
	
	//destroy-method="close":当数据库连接不使用的时候,将该连接重新放到数据池中
    @Bean(name=DataSources.DB1,destroyMethod="close")
    @ConfigurationProperties(prefix = "spring.datasource-db1")
    public DataSource dataSourceDB1() {
    	// 创建数据源
        return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }

    @Bean(name=DataSources.DB2,destroyMethod="close")
    @ConfigurationProperties(prefix = "spring.datasource-db2")
    public DataSource dataSourceDB2() {
    	// 创建数据源
        return DataSourceBuilder.create().type(DruidDataSource.class).build();
    }
    
    // 支持JdbcTemplate (可选)
    @Bean(DataSources.DB1_JDBCTEMPLATE)
    public JdbcTemplate db1JdbcTemplate(
            @Qualifier(DataSources.DB1) DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
    
    @Bean(DataSources.DB2_JDBCTEMPLATE)
    public JdbcTemplate db2JdbcTemplate(
            @Qualifier(DataSources.DB2) DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
    
    // 支持事务(可选)
    @Bean(DataSources.DB1_TRANSACTION)
    public DataSourceTransactionManager db1TransactionManager(
            @Qualifier(DataSources.DB1) DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    
    @Bean(DataSources.DB2_TRANSACTION)
    public DataSourceTransactionManager db2TransactionManager(
            @Qualifier(DataSources.DB2) DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    

}


Step3 配置多个数据源

1. 扫描包的路径,不同的数据源扫描的包路径不同
2. 通过@Qualifier指定注入的数据源
3. Mybatis如果使用xml方式,配置文件中有配置项,通过前缀加载对应的配置项

MybatisDB1Config

package com.artisan.config;

import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
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;

@Configuration
//  db1的接口类的包名
@MapperScan(basePackages = { "com.artisan.dao.db1" }, sqlSessionFactoryRef = "db1SqlSessionFactoryBean")
public class MybatisDB1Config {

	@Autowired
	// 必须指定注入哪个数据源,否则找到多个会注入失败
	@Qualifier(DataSources.DB1)
	private DataSource db1;
	

	@Bean(name = "db1SqlSessionFactoryBean")
	@ConfigurationProperties(prefix = "mybatis-db1") // 和 配置文件中的前缀保持一致
	// @Primary 如果SqlSessionFactoryBean的名字和MybatisDB2Config中的一致(默认方法名),需要加上这个注解,优先注入该SqlSessionFactoryBean
	// 这里我们通过bean指定了name,并且方法名也不一样,所以如果情况不一样,看是否需要加入@Primary 。 如果需要两个方法上加一个就行了,都加的话,spring又找不到bean注入啦。。
	public SqlSessionFactoryBean db1SqlSessionFactoryBean() throws Exception {
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		// 配置数据源
		sqlSessionFactoryBean.setDataSource(db1);
		// 如下的两行代码仅仅用于*.xml文件,如果整个持久层操作没用到xml文件的话,比如使用注解的方式,则无需加
		// 解决配置到配置文件中通过*配置找不到mapper文件的问题。 如果不设置这一行,在配置文件中,只能使用数组的方式一个个的罗列出来,并且要指定具体的文件名
		sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper_db1/*.xml"));
		// 也可以通过在application.yml中配置
		//sqlSessionFactoryBean.setTypeAliasesPackage("com.artisan.domain.db1");
		return sqlSessionFactoryBean;
	}
	
	// 可选,如果需要通过SqlSessionTemplate来操作持久层就通过@Bean实例化,我们这个例子中没用到,随手写出来了
	@Bean(name="db1SqlSessionTemplate")
	public SqlSessionTemplate db1SqlSessionTemplate() throws Exception {
		SqlSessionTemplate template = new SqlSessionTemplate(db1SqlSessionFactoryBean().getObject());
		return template;
	}

}

MybatisDB2Config

package com.artisan.config;


import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
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.core.io.support.PathMatchingResourcePatternResolver;

@Configuration
@MapperScan(basePackages = { "com.artisan.dao.db2" },sqlSessionFactoryRef="db2SqlSessionFactoryBean" ) // 扫描的mybatis接口类的包名
public class MybatisDB2Config {

	@Autowired
	// 必须指定注入哪个数据源,否则找到多个会注入失败
	@Qualifier(DataSources.DB2)
	private DataSource db2;

	@Bean(name="db2SqlSessionFactoryBean")
	@ConfigurationProperties(prefix = "mybatis-db2") // 和 配置文件中的前缀保持一致
	public SqlSessionFactoryBean db2SqlSessionFactoryBean() throws Exception {
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		// 配置数据源
		sqlSessionFactoryBean.setDataSource(db2);
		// 解决配置到配置文件中通过*配置找不到mapper文件的问题。 如果不设置这一行,在配置文件中,只能使用数组的方式一个个的罗列出来,并且要指定具体的文件名
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper_db2/*.xml"));
		return sqlSessionFactoryBean;
	}
	
	
	// 可选,如果需要通过SqlSessionTemplate来操作持久层就通过@Bean实例化,我们这个例子中没用到,随手写出来了
	@Bean(name = "db2SqlSessionTemplate")
	public SqlSessionTemplate db2SqlSessionTemplate() throws Exception {
		SqlSessionTemplate template = new SqlSessionTemplate(db2SqlSessionFactoryBean().getObject());
		return template;
	}

}


验证测试

数据库表、Domain , Dao , Service,Controller中的代码见下面的Github连接,很简单,就不贴了,只说重点

贴下数据库的初始数据吧

db1:
在这里插入图片描述
db2:

在这里插入图片描述

启动Spring Boot工程,

访问 http://localhost:8080/db1?id=1

在这里插入图片描述

访问 http://localhost:8080/db2?id=1

在这里插入图片描述


支持事务

Step1 配置类中通过@Bean初始化DataSourceTransactionManager

在这里插入图片描述


Step2 如何使用呢? @Transactional(DataSources.DB1_TRANSACTION)

在这里插入图片描述


Step3 验证事务

访问: http://localhost:8080/db1/transTest
在这里插入图片描述

数据库中的数据

在这里插入图片描述

为了方便验证 artisanMapper.updateArtisan(artisan)中故意写错了个字段名,让其抛出异常,测试回滚。 执行方法后,可以看到因为第二个方法报错,第一个方法中的插入的数据也回滚了 。


顺便说下 集成JdbcTemplate

持久层我们这里用的Mybatis,有些同学说我想用JdbcTemplate呢

Step1 配置类中通过@Bean初始化每个数据库实例对应的JdbcTemplate

在这里插入图片描述


Step2 如何使用呢? @Autowired @Qualifier(DataSources.DB1_JDBCTEMPLATE)

在这里插入图片描述


Step3 验证

在这里插入图片描述

启动工程,访问 http://localhost:8080/db1/jdbcTemplateTest

查看数据

在这里插入图片描述


代码

https://github.com/yangshangwei/MultiDataSource

猜你喜欢

转载自blog.csdn.net/yangshangwei/article/details/86755745