文档章节

springboot多数据源实现

c
 ccman996
发布于 06/25 22:05
字数 595
阅读 69
收藏 8

1、配置数据源,主从两个数据源

/**
 * 多数据源配置(读写主从分离)
 * @author liucc
 */
@Configuration
@EnableTransactionManagement
public class DataSourceConfig {


    public static final String SLAVE_KEY = "slave";
    public static final String MASTER_KEY = "master";

    /**
     * maste setting
     */
    @Bean(initMethod = "init", destroyMethod = "close",name = "masterDataSource")
    @ConfigurationProperties("user.master")
    @Primary
    public DruidDataSource masterDataSource() {
        return new DruidDataSource();
    }


    /**
     * slave setting
     */
    @Bean(initMethod = "init", destroyMethod = "close",name = "slaveDataSource")
    @ConfigurationProperties("user.slave")
    public DruidDataSource slaveDataSource() {
        return new DruidDataSource();
    }


    @Bean(name="dynamicDataSource")
    public ReplicationRoutingDataSource dynamicDataSource(@Qualifier("masterDataSource") DruidDataSource master, @Qualifier("slaveDataSource") DruidDataSource slave) throws IOException {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceConfig.MASTER_KEY, master);
        targetDataSources.put(DataSourceConfig.SLAVE_KEY, slave);

        ReplicationRoutingDataSource dynamicDataSource = new ReplicationRoutingDataSource();
        dynamicDataSource.setDefaultTargetDataSource(master);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }



    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlFactory = new SqlSessionFactoryBean();
        sqlFactory.setDataSource(dataSource);
        sqlFactory.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
        return sqlFactory.getObject();
    }

    @Bean
    public DataSourceTransactionManager transactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) throws IOException {
        return new DataSourceTransactionManager(dataSource);
    }
}

 

2、继承AbstractRoutingDataSource类,实现determineCurrentLookupKey方法动态选择数据源datasource

/**
 * 多数据源路由
 * @author liucc
 */
public class ReplicationRoutingDataSource extends AbstractRoutingDataSource {

    private static final Logger logger = LoggerFactory.getLogger(ReplicationRoutingDataSource.class);

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    /**
     * Slave if the current transaction is in read-only mode, or master.
     */
    @Override
    protected Object determineCurrentLookupKey() {
        String lookupKey = contextHolder.get();
        if(StringUtils.isBlank(lookupKey)){
            lookupKey = DataSourceConfig.MASTER_KEY;
        }
        logger.info("connected DataSource :{}", lookupKey);
        return lookupKey;
    }

    public static void selectSlave(){
        contextHolder.set(DataSourceConfig.SLAVE_KEY);
    }

    public static void selectMaster(){
        contextHolder.set(DataSourceConfig.MASTER_KEY);
    }
}

 

 

3、自定义注解,通过在方法上添加注解来选择需要的数据源

@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface SelectDataSource {

    String value() default DataSourceConfig.MASTER_KEY;

}

4、通过Aspect切面来解析注解

/**
 * 数据源自动选择切面
 * @author liucc
 */
@Aspect
@Component
public class DataSourceSelectAspect {

    private static final Logger logger = LoggerFactory.getLogger(DataSourceSelectAspect.class);

    @Before("@annotation(selectDataSource)")
    public void before(SelectDataSource selectDataSource) {
        if(DataSourceConfig.SLAVE_KEY.equals(selectDataSource.value())){
            ReplicationRoutingDataSource.selectSlave();
        }
        else{
            ReplicationRoutingDataSource.selectMaster();
        }
    }

}

 

 

5、使用,直接在service方法上添加注解@SelectDataSource

@Service
public class TestService{

    @Autowired
    private UserInfoMapper userInfoMapper;

    @SelectDataSource(DataSourceConfig.SLAVE_KEY)
    public List<User> getUserInfo(String userid){
          return userInfoMapper.get(userid);
    }
}

 

附上

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="cacheEnabled" value="true"/>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
        <setting name="multipleResultSetsEnabled" value="true"/>
        <setting name="useColumnLabel" value="true"/>
        <setting name="useGeneratedKeys" value="true"/>
        <setting name="autoMappingBehavior" value="PARTIAL"/>
        <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <setting name="defaultStatementTimeout" value="25"/>
        <setting name="defaultFetchSize" value="100"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="callSettersOnNulls" value="true"/>
        <setting name="logImpl" value="LOG4J2" />
    </settings>
</configuration>

 

application-db.properties

user.master.url=jdbc:127.0.0.1:3306/user_test?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&failOverReadOnly=false&allowMultiQueries=true&useSSL=false
user.master.username=test
user.master.password=test
user.master.initialSize=3
user.master.minIdle=3
user.master.maxActive=5
user.master.maxWait=4
user.master.timeBetweenEvictionRunsMillis=60000
user.master.minEvictableIdleTimeMillis=300000
user.master.testWhileIdle=true
user.master.testOnBorrow=false
user.master.validationQuery=SELECT 1
user.master.driverClassName=com.mysql.jdbc.Driver
user.master.connectionInitSqls=set names utf8mb4


user.slave.url=jdbc:mysql://127.0.0.2:3306/user_test?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&failOverReadOnly=false&allowMultiQueries=true&useSSL=false
user.slave.username=test
user.slave.password=test
user.slave.initialSize=3
user.slave.minIdle=3
user.slave.maxActive=5
user.slave.maxWait=4
user.slave.timeBetweenEvictionRunsMillis=60000
user.slave.minEvictableIdleTimeMillis=300000
user.slave.testWhileIdle=true
user.slave.testOnBorrow=false
user.slave.validationQuery=SELECT 1
user.slave.driverClassName=com.mysql.jdbc.Driver
user.slave.connectionInitSqls=set names utf8mb4
                                                         
                                                         
                                                                                                                 

 

© 著作权归作者所有

c
粉丝 1
博文 9
码字总数 2222
作品 0
厦门
私信 提问
SpringBootBucket 1.0.0 发布,SprintBoot 全家桶

Spring Boot 现在已经成为Java 开发领域的一颗璀璨明珠,它本身是包容万象的,可以跟各种技术集成。 本项目对目前Web开发中常用的各个技术,通过和SpringBoot的集成,并且对各种技术通过“一...

一刀
2018/03/05
7.3K
17
恒宇少年/spring-boot-chapter

简书整套文档以及源码解析 专题 专题名称 专题描述 001 Spring Boot 核心技术 讲解SpringBoot一些企业级层面的核心组件 002 Spring Cloud 核心技术 对Spring Cloud核心技术全面讲解 003 Quer...

恒宇少年
2018/04/19
0
0
【SpringBoot2.0系列05】SpringBoot之整合Mybatis

【SpringBoot2.0系列01】初识SpringBoot 【SpringBoot2.0系列02】SpringBoot之使用Thymeleaf视图模板 【SpringBoot2.0系列03】SpringBoot之使用freemark视图模板 【SpringBoot2.0系列04】Spr...

余空啊
2018/08/14
0
0
Spring Boot 全家桶 - SpringBootBucket

Spring Boot 现在已经成为Java 开发领域的一颗璀璨明珠,它本身是包容万象的,可以跟各种技术集成。 本项目对目前Web开发中常用的各个技术,通过和SpringBoot的集成,并且对各种技术通过“一...

一刀
2018/03/05
0
1
SpringBootBucket 2.0.4 发布,代号“傲娇的小二晶”

SpringBootBucket 自从1.0.0版本发布后就有好多人喜欢,目前码云上面star数量接近1.2k。上个月还收到了红薯签名的1000 star奖杯,这个我自己也觉得很惊讶。 由于SpringBoot 1.x官方将终止维护...

一刀
2018/09/16
1K
4

没有更多内容

加载失败,请刷新页面

加载更多

springmvc 流程

1, 首先用户发现 http 请求 到 服务器 ,进入 到 servlet 容器中,servlet 容器 解析请求,和数据 , 以及 httphandler . 解析完的 请求body 数据流。 2. 进入 用户自定义的 filter 过滤器,...

之渊
41分钟前
1
0
django2.2 用户登录练习完整版(待改善)

主要配置: settings.py配置: #数据库配置import pymysqlpymysql.install_as_MySQLdb()DATABASES = {    'default': {        'ENGINE': 'django.db.backends.mysql',  ......

平头哥-Enjoystudy
今天
2
0
if __name__ == '__main__'

通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明');在你自己眼中,你是你自己(__name__ == '__main__')。 if __name__ == '__main__'的意思是......

Nagisa丶夜雨
今天
4
0
Skynet 服务创建流程

Skynet 服务创建流程 根据设计综述 Skynet 是为了让服务器充分利用多核优势,将不同的业务放在独立的执行环境中处理。 Skynet 核心功能是加载一个 C 模块(动态库),模块用数字 id 标识,作...

ylme
今天
4
0
js中为什么你不敢用 “==”

前言 类型转换在各个语言中都存在,而在 JavaScript 中由于缺乏对其的了解而不慎在使用中经常造成bug被人诟病。为了避免某些场景下的意外,甚至推崇直接使用 Strict Equality( === )来代替 ...

JamesView
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部