史上最简单的spring boot和mybatis结合的多数据源配置

本文将介绍使用Spring Boot集成Mybatis并实现主从库分离的实现(适用于多数据源),网上有很多讲述多数据源的,有的太复杂,有的不生效,我下面的是直接可以用的,而且是最简单的,这里写出来,和大家共同学习,如有不对,请指出来,感谢,本人企鹅:761173739,废话少说,直接来:

1.pom的依赖,这里太多,后期我再整理一个最简洁的:

com.sunny.study
	multiple-datasource
	0.0.1-SNAPSHOT
	jar

	springboot-multiple-datasource
	多数据源

	
		org.springframework.boot
		spring-boot-starter-parent
		2.0.3.RELEASE
		 
	

	
		UTF-8
		UTF-8
		1.8
	

	
		
			org.springframework.boot
			spring-boot-starter-aop
		

		
		
			org.springframework.boot
			spring-boot-starter-web
			
				
					org.springframework.boot
					spring-boot-starter-tomcat
				
			
		
		
			org.springframework.boot
			spring-boot-starter-undertow
		
		
		
			org.mybatis.spring.boot
			mybatis-spring-boot-starter
			1.3.2
		

		
		
			com.github.pagehelper
			pagehelper-spring-boot-starter
			1.2.4
		
		
			org.springframework.boot
			spring-boot-starter-test
			test
		

		
		
			org.apache.commons
			commons-lang3
		

		
		
			com.alibaba
			druid
			1.0.13
		
		
			mysql
			mysql-connector-java
		

		
		
			org.springframework.boot
			spring-boot-configuration-processor
			true
		
	




注意:项目是通过扩展mybatis-spring-boot-starter的org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration来实现多数据源注入的,这也是最简洁的方式



2.application.yml:

# 数据库访问配置
# 使用druid数据源
druid:
    type: com.alibaba.druid.pool.DruidDataSource
    master:
        url: jdbc:mysql://127.0.0.1:3306/test_db?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true&useSSL=false
        username: root
        password: root

        driver-class-name: com.mysql.jdbc.Driver
        filters: stat
        maxActive: 20
        initialSize: 3
        maxWait: 60000
        minIdle: 3
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: select 'x'
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
        maxOpenPreparedStatements: 20

    slave:
        url: jdbc:mysql://127.0.0.1:3306/test_db2?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true&useSSL=false
        username: root
        password: root

        driver-class-name: com.mysql.jdbc.Driver
        filters: stat
        maxActive: 20
        initialSize: 3
        maxWait: 60000
        minIdle: 3
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: select 'x'
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
        maxOpenPreparedStatements: 20



3.创建数据源:

@Configuration
@EnableTransactionManagement
public class DataSourceConfiguration {

    @Value("${druid.type}")
    private Class dataSourceType;

    @Bean(name="masterDataSource")
    @Primary
    @ConfigurationProperties(prefix = "druid.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().type(dataSourceType).build();
    }

    @Bean(name = "slaveDataSource")
    @ConfigurationProperties(prefix = "druid.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().type(dataSourceType).build();
    }
}


4.将多数据源注入到sqlSessionFactory中:

切记注意:请看代码中的注释,否则不生效


4.1以下是mybatis-spring-boot-starter1.1.1版本的配置
@Configuration
@AutoConfigureAfter({DataSourceConfiguration.class})
public class MybatisConfiguration extends MybatisAutoConfiguration {

    public MybatisConfiguration(MybatisProperties properties, ObjectProvider interceptorsProvider,
                                ResourceLoader resourceLoader, ObjectProvider databaseIdProvider,
                                ObjectProvider> configurationCustomizersProvider) {
        super(properties, interceptorsProvider, resourceLoader, databaseIdProvider, configurationCustomizersProvider);
    }


    private static Log logger = LogFactory.getLog(MybatisConfiguration.class);

    @Resource(name = "masterDataSource")
    private DataSource masterDataSource;
    @Resource(name = "slaveDataSource")
    private DataSource slaveDataSource;

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        logger.info("-------------------- 重载父类 sqlSessionFactory init ---------------------");
        return super.sqlSessionFactory(roundRobinDataSouceProxy());
    }

    
    public AbstractRoutingDataSource roundRobinDataSouceProxy(){
        DbRouteDataSource proxy = new DbRouteDataSource();
        @SuppressWarnings("unchecked")
        Map targetDataResources = new ClassLoaderRepository.SoftHashMap();
        targetDataResources.put(DbContextHolder.DbType.MASTER,masterDataSource);
        targetDataResources.put(DbContextHolder.DbType.SLAVE,slaveDataSource);
        proxy.setDefaultTargetDataSource(masterDataSource);
        proxy.setTargetDataSources(targetDataResources);
        return proxy;
    }
}
4.2以下是mybatis-spring-boot-starter1.3版本的配置,红色地方需要注意
@Configuration
@AutoConfigureAfter({DataSourceConfiguration.class})
public class MybatisConfiguration extends MybatisAutoConfiguration {

    public MybatisConfiguration(MybatisProperties properties, ObjectProvider interceptorsProvider,
                                ResourceLoader resourceLoader, ObjectProvider databaseIdProvider,
                                ObjectProvider> configurationCustomizersProvider) {
        super(properties, interceptorsProvider, resourceLoader, databaseIdProvider, configurationCustomizersProvider);
    }


    private static Log logger = LogFactory.getLog(MybatisConfiguration.class);

    @Resource(name = "masterDataSource")
    private DataSource masterDataSource;
    @Resource(name = "slaveDataSource")
    private DataSource slaveDataSource;

    @Bean
    @Override
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        logger.info("-------------------- 重载父类 sqlSessionFactory init ---------------------");
        return super.sqlSessionFactory(roundRobinDataSouceProxy());
    }


    public AbstractRoutingDataSource roundRobinDataSouceProxy(){
    	DbRouteDataSource proxy = new DbRouteDataSource();
        Map targetDataResources = new HashMap(2);
        targetDataResources.put(DbContextHolder.DbType.MASTER,masterDataSource);
        targetDataResources.put(DbContextHolder.DbType.SLAVE,slaveDataSource);
        proxy.setDefaultTargetDataSource(masterDataSource);
        proxy.setTargetDataSources(targetDataResources);
        proxy.afterPropertiesSet();
        return proxy;

    }
}



5.实现读写分离(多数据源分离):

这里主要思路如下:
1-将不同的数据源标识记录在ThreadLocal中
2-通过注解标识出当前的service方法使用哪个库
3-通过Spring AOP实现拦截注解并注入不同的标识到threadlocal中
4-获取源的时候通过threadlocal中不同的标识给出不同的sqlSession

标识存放ThreadLocal的实现

public class DbContextHolder {

    public enum DbType{
        /***
         * 主数据源
         */
        MASTER,
        /***
         * 从数据源
         */
        SLAVE
    }

    private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDbType(DbType dbType){
        if(dbType==null){
            throw new NullPointerException();
        }else{
            CONTEXT_HOLDER.set(dbType);
        }
    }

    public static DbType getDbType(){
        return CONTEXT_HOLDER.get()==null? DbType.MASTER:CONTEXT_HOLDER.get();
    }

    public static void clearDbType() {
        CONTEXT_HOLDER.remove();
    }

}


注解实现

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SlaveDataSource {
}



Spring AOP对注解的拦截

@Aspect
@Component
public class SlaveDataSourceInterceptor implements Ordered {

    public static final Logger logger = LoggerFactory.getLogger(SlaveDataSourceInterceptor.class);

    @Around("@annotation(slaveDataSource)")
    public Object proceed(ProceedingJoinPoint proceedingJoinPoint, SlaveDataSource slaveDataSource) throws Throwable {
        try {
            logger.debug("set database connection to read only");
            DbContextHolder.setDbType(DbContextHolder.DbType.SLAVE);
            Object result = proceedingJoinPoint.proceed();
            return result;
        }finally {
            DbContextHolder.clearDbType();
            logger.debug("restore database connection");
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }
}


使用方式:

@SlaveDataSource
@RequestMapping(value = "/abc/xxx", method = RequestMethod.POST)
    public Object queryList(@RequestBody Object vo) throws BaseException {
       
        return "ok";
    }



你可能感兴趣的:(史上最简单的spring boot和mybatis结合的多数据源配置)