栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多数据源读写分离

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多数据源读写分离

本文主要涉及对技术mybatis和spring基础开源框架的使用

核心逻辑:实现拦截器,利用MappedStatement去判断sql类型,通determineCurrentLookupKey判断使用的数据源id,进行数据源的选择

配置文件(application.properties)
datasource.write.driver-class-name=com.mysql.jdbc.Driver
datasource.write.url=jdbc:mysql://172.198.16.10:3306/test
datasource.write.username=root
datasource.write.password=123456

datasource.read.driver-class-name=com.mysql.jdbc.Driver
datasource.read.url=jdbc:mysql://172.198.16.11:3306/test
datasource.read.username=root
datasource.read.password=123456

 threadlocal基本方法封装
package com.iqc.manydatasource;


public class DataSourceHolder {

    public static final String WRITE_DATASOURCE = "write";
    public static final String READ_DATASOURCE = "read";

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


    public static void putDataSource(String dataSource) {
        local.set(dataSource);
    }

    public static String getDataSource() {
        return local.get();
    }
}

configuration配置
package com.iqc.manydatasource;

import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
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;

@Configuration
public class DataSourcePropertiesConfig {

    @Primary
    @Bean("writeDataSourceProperties")
    @ConfigurationProperties("datasource.write")
    public DataSourceProperties writeDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean("readDataSourceProperties")
    @ConfigurationProperties("datasource.read")
    public DataSourceProperties readDataSourceProperties() {
        return new DataSourceProperties();
    }
}

determineCurrentLookupKey配置
package com.iqc.manydatasource;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

import static com.iqc.manydatasource.DataSourceHolder.READ_DATASOURCE;
import static com.iqc.manydatasource.DataSourceHolder.WRITE_DATASOURCE;

@Component
public class MultipleDataSource extends AbstractRoutingDataSource {

    @Resource(name = "writeDataSourceProperties")
    private DataSourceProperties writeProperties;

    @Resource(name = "readDataSourceProperties")
    private DataSourceProperties readProperties;


    
    @Override
    public void afterPropertiesSet() {
        DataSource writeDataSource =
            writeProperties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
        DataSource readDataSource =
            readProperties.initializeDataSourceBuilder().type(DruidDataSource.class).build();

        setDefaultTargetDataSource(writeDataSource);

        Map dataSourceMap = new HashMap<>();
        dataSourceMap.put(WRITE_DATASOURCE, writeDataSource);
        dataSourceMap.put(READ_DATASOURCE, readDataSource);
        setTargetDataSources(dataSourceMap);

        super.afterPropertiesSet();
    }

    
    @Override
    protected Object determineCurrentLookupKey() {
        String key = DataSourceHolder.getDataSource();
        //进行置空操作,避免出现select后update导致进入下方if判断
        DataSourceHolder.putDataSource(null);
        if (key == null) {
             // default datasource
            return WRITE_DATASOURCE;
        }

        return key;
    }
}

sql拦截器配置
package com.iqc.manydatasource;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Properties;

@Component
@Intercepts({
        @Signature(type = Executor.class, method = "update",
                args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
        })
public class MybatisDataSourceInterceptor implements Interceptor {
    
    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();
        if(!synchronizationActive) {
            Object[] objects = invocation.getArgs();
            MappedStatement ms = (MappedStatement) objects[0];
            //进行sql拦截判断是UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH中的哪个。
            // select进读库,其余进写库,这里可以增加判断条件去走不同库
            if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {
                DataSourceHolder.putDataSource(DataSourceHolder.READ_DATASOURCE);
            }
        }

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/986876.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号