ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

MyBatis SpringBoot2.0 数据库读写分离

2019-02-28 18:53:45  阅读:232  来源: 互联网

标签:SpringBoot2.0 数据源 读写 springframework annotation org MyBatis import public


1、自定义DataSource

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @Description 动态数据源
 * AbstractRoutingDataSource(每执行一次数据库,动态获取DataSource)
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}

2、数据源切换器

import java.util.ArrayList;
import java.util.List;

/**
 * @Description 动态数据源上下文管理
 */
public class DynamicDataSourceContextHolder {

    //存放当前线程使用的数据源类型信息
    private static final ThreadLocal<Object> contextHolder = new ThreadLocal<>();
    //存放数据源id
    public static List<Object> dataSourceIds = new ArrayList<>();
    
    
    //当从库数据源大于1个时,可以配置轮询方式
    public static List<Object> slaveDataSourceKeys = new ArrayList<>();


    //设置数据源
    public static void setDataSourceType(String dataSourceType) {
            if(dataSourceIds.contains(dataSourceType)) {
                contextHolder.set(dataSourceType);
            }
    }

    //获取数据源
    public static Object getDataSourceType() {
        return contextHolder.get();
    }

    //清除数据源
    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

3、代理类事物切换数据源

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Description 动态数据源通知
 */
@Aspect
@Order(-1)//保证在@Transactional之前执行
@Component
public class DynamicDattaSourceAspect {

    //改变数据源,方法上存在事物的注解,则走主库
    @Before("@annotation(transactional)")
    public void changeDataSource(JoinPoint joinPoint, Transactional transactional) {
           DynamicDataSourceContextHolder.setDataSourceType("master");
    }

    @After("@annotation(transactional)")
    public void clearDataSource(JoinPoint joinPoint, Transactional transactional) {
        DynamicDataSourceContextHolder.clearDataSourceType();
    }
}

4、数据源Bean注册器

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.flyway.FlywayDataSource;
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.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import tk.mybatis.spring.annotation.MapperScan;

/**
 * @Description 注册动态数据源
 * 初始化数据源和提供了执行动态切换数据源的工具类
 */
@Configuration
@MapperScan(basePackages="com.xxxx.*.mapper")
public class DynamicDataSourceRegister{
    protected Logger logger = LoggerFactory.getLogger(getClass());


    @Value("${datasource.type}")
    private Class<? extends DataSource> dataSourceType;


    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dynamicDataSource());
        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
        sessionFactory.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath*:mapper/*Mapper.xml"));
        Resource resource = pathMatchingResourcePatternResolver.getResource("classpath:mybatis-setting.xml");
        sessionFactory.setConfigLocation(resource);
        return sessionFactory.getObject();
    }

    @FlywayDataSource//指定主库为flyway的数据源
    @Bean(name = "masterDataSource")
    @ConfigurationProperties(prefix = "master.datasource")
    public DataSource masterDataSource(){
        return DataSourceBuilder.create().type(dataSourceType).build();
    }

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

    @Bean("dynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicRoutingDataSource = new DynamicDataSource();
        Map<Object, Object> dataSourceMap = new HashMap<>(4);
        dataSourceMap.put("master", masterDataSource());
        dataSourceMap.put("slaveDataSource", slaveDataSource());

        // 将 slave 数据源作为默认指定的数据源
        dynamicRoutingDataSource.setDefaultTargetDataSource(slaveDataSource());
        // 将 master 和 slave 数据源作为指定的数据源
        dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);

        // 将数据源的 key 放到数据源上下文的 key 集合中,用于切换时判断数据源是否有效
        DynamicDataSourceContextHolder.dataSourceIds.addAll(dataSourceMap.keySet());

        // 将 Slave 数据源的 key 放在集合中,用于轮循
        DynamicDataSourceContextHolder.slaveDataSourceKeys.addAll(dataSourceMap.keySet());
        DynamicDataSourceContextHolder.slaveDataSourceKeys.remove("master");
        return dynamicRoutingDataSource;
    } 
    
    @Bean
    public PlatformTransactionManager transactionManager() {
        
        return new DataSourceTransactionManager(dynamicDataSource());
    }
    

}

 

标签:SpringBoot2.0,数据源,读写,springframework,annotation,org,MyBatis,import,public
来源: https://www.cnblogs.com/binz/p/10452288.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有