springboot+mybatis实现数据库读写分离

本文不包含数据库主从配置。

实现思路:在项目中配置多数据源,通过代码控制访问哪一个数据源。

spring-jdbc为我们提供了AbstractRoutingDataSource,DataSource的抽象实现,基于查找键,返回不通不同的数据源。编写我们自己的动态数据源类DynamicDataSource继承AbstractRoutingDataSource,实现determineCurrentLookupKey方法。

配置一个spring config类DataSourceConfig,把DynamicDataSource初始化。

配置SqlSessionFactory,注入我们自定义的数据源DynamicDataSource。

通过AOP切入设置所需要的数据源,比如插入或者更新使用主数据源,查询使用从读数据源

#主数据库设置
spring.datasource.master.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
spring.datasource.master.driverClassName=com.mysql.jdbc.Driver
spring.datasource.master.username=root
spring.datasource.master.password=root
spring.datasource.maseter.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.master.initialSize=5
spring.datasource.master.minIdle=1
spring.datasource.master.maxActive=50
spring.datasource.master.maxWait=60000
spring.datasource.master.minEvictableIdleTimeMillis=300000

#从数据库设置
spring.datasource.slave.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
spring.datasource.slave.driverClassName=com.mysql.jdbc.Driver
spring.datasource.slave.username=root
spring.datasource.slave.password=root
spring.datasource.slave.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.slave.initialSize=5
spring.datasource.slave.minIdle=1
spring.datasource.slave.maxActive=50
spring.datasource.slave.maxWait=60000
spring.datasource.slave.minEvictableIdleTimeMillis=300000

@Configuration
public class DataSourceConfig {

    @Value("${spring.datasource.master.url}")
    private String masterUrl;
    @Value("${spring.datasource.master.driverClassName}")
    private String masterDriverClassName;
    @Value("${spring.datasource.master.username}")
    private String masterUsername;
    @Value("${spring.datasource.master.password}")
    private String masterPassword;
    @Value("${spring.datasource.master.initialSize}")
    private Integer masterInitialSize;
    @Value("${spring.datasource.master.minIdle}")
    private Integer masterMinIdle;
    @Value("${spring.datasource.master.maxWait}")
    private Long masterMaxWait;
    @Value("${spring.datasource.master.maxActive}")
    private Integer masterMaxActive;
    @Value("${spring.datasource.master.minEvictableIdleTimeMillis}")
    private Integer masterMinEvictableIdleTimeMillis;

    @Value("${spring.datasource.slave.url}")
    private String slaveUrl;
    @Value("${spring.datasource.slave.driverClassName}")
    private String slaveDriverClassName;
    @Value("${spring.datasource.slave.username}")
    private String slaveUsername;
    @Value("${spring.datasource.slave.password}")
    private String slavePassword;
    @Value("${spring.datasource.slave.initialSize}")
    private Integer slaveInitialSize;
    @Value("${spring.datasource.slave.minIdle}")
    private Integer slaveMinIdle;
    @Value("${spring.datasource.slave.maxWait}")
    private Long slaveMaxWait;
    @Value("${spring.datasource.slave.maxActive}")
    private Integer slaveMaxActive;
    @Value("${spring.datasource.slave.minEvictableIdleTimeMillis}")
    private Integer slaveMinEvictableIdleTimeMillis;

    public DataSourceConfig() {
        System.out.println("#DataSourceConfig#");
    }

    public DataSource master() {
        System.out.println("# master druid#");
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(masterUrl);
        datasource.setDriverClassName(masterDriverClassName);
        datasource.setUsername(masterUsername);
        datasource.setPassword(masterPassword);
        datasource.setInitialSize(masterInitialSize);
        datasource.setMinIdle(masterMinIdle);
        datasource.setMaxWait(masterMaxWait);
        datasource.setMaxActive(masterMaxActive);
        datasource.setMinEvictableIdleTimeMillis(masterMinEvictableIdleTimeMillis);
        try {
            datasource.setFilters("stat,wall");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return datasource;
    }

    public DataSource salve() {
        System.out.println("# slave slave#");
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(slaveUrl);
        datasource.setDriverClassName(slaveDriverClassName);
        datasource.setUsername(slaveUsername);
        datasource.setPassword(slavePassword);
        datasource.setInitialSize(slaveInitialSize);
        datasource.setMinIdle(slaveMinIdle);
        datasource.setMaxWait(slaveMaxWait);
        datasource.setMaxActive(slaveMaxActive);
        datasource.setMinEvictableIdleTimeMillis(slaveMinEvictableIdleTimeMillis);
        try {
            datasource.setFilters("stat,wall");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return datasource;
    }
public class DynamicDataSource extends AbstractRoutingDataSource {

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

    @Override
    protected Object determineCurrentLookupKey() {
        return contextHolder.get();
    }

    public static enum DatabaseType {
        Master,Slave
    }

    public static void master() {
        contextHolder.set(DatabaseType.Master);
    }

    public static void slave() {
        contextHolder.set(DatabaseType.Slave);
    }

}

    @Bean
    public DynamicDataSource dynamicDataSource() {
        DataSource master = master();
        DataSource slave = salve();
        Map<Object,Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DynamicDataSource.DatabaseType.Master, master);
        targetDataSources.put(DynamicDataSource.DatabaseType.Slave, slave);
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);
        dataSource.setDefaultTargetDataSource(master);
        return dataSource;
    }
}
@Configuration
@AutoConfigureAfter({DataSourceConfig.class})
public class MybatisConfig {

    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dynamicDataSource);
        SqlSessionFactory sqlSessionFactory = null;
        try {
            sqlSessionFactory = bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        MapperHelper mapperHelper = new MapperHelper();
        Config config = new Config();
        config.setNotEmpty(true);
        mapperHelper.setConfig(config);
        mapperHelper.registerMapper(Mapper.class);
        mapperHelper.processConfiguration(sqlSessionFactory.getConfiguration());
        return sqlSessionFactory;
    }

    @Bean
    public MapperScannerConfigurer scannerConfigurer() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
//        configurer.setSqlSessionTemplateBeanName("sqlSession");
        configurer.setBasePackage("com.luke.hu.dao");
        configurer.setMarkerInterface(Mapper.class);
        return configurer;
    }
}
@Aspect
@Component
public class DataSourceAOP {

    @Before("execution(* com.luke.hu.dao..*.insert*(..)) || execution(* com.luke.hu.dao..*.update*(..))")
    public void setWriteDataSourceType() {
        DynamicDataSource.master();
        System.out.println("切换到master");
    }

    @Before("execution(* com.luke.hu.dao..*.select*(..))")
    public void setReadDataSourceType() {
        DynamicDataSource.slave();
        System.out.println("切换到slave");
    }
}

原文地址:https://www.cnblogs.com/twood/p/10199123.html

时间: 2024-07-31 14:40:52

springboot+mybatis实现数据库读写分离的相关文章

Spring+MyBatis实现数据库读写分离方案

方案1通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactoryBean对象的mapperLocations属性制定两个读写数据源的配置文件.将所有读的操作配置在读文件中,所有写的操作配置在写文件中. 优点:实现简单缺点:维护麻烦,需要对原有的xml文件进行重新修改,不支持多读,不易扩展实现方式 <bean id="abstractDataSource" abstract="true" class="com

spring+mybatis利用interceptor(plugin)兑现数据库读写分离

使用spring的动态路由实现数据库负载均衡 系统中存在的多台服务器是“地位相当”的,不过,同一时间他们都处于活动(Active)状态,处于负载均衡等因素考虑,数据访问请求需要在这几台数据库服务器之间进行合理分配, 这个时候,通过统一的一个DataSource来屏蔽这种请求分配的需求,从而屏蔽数据访问类与具体DataSource的耦合: 系统中存在的多台数据库服务器现在地位可能相当也可能不相当,但数据访问类在系统启动时间无法明确到底应该使用哪一个数据源进行数据访问,而必须在系统运行期间通过某种条

Spring + Mybatis项目实现数据库读写分离

主要思路:通过实现AbstractRoutingDataSource类来动态管理数据源,利用面向切面思维,每一次进入service方法前,选择数据源. 1.首先pom.xml中添加aspect依赖 <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.9</version> </depen

Spring+Mybatis实现主从数据库读写分离

Spring+Mybatis实现主从数据库读写分离 采用配置+注解的方式. 自定义@DataSource注解 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME

Mybatis多数据源读写分离(注解实现)

#### Mybatis多数据源读写分离(注解实现) ------ 首先需要建立两个库进行测试,我这里使用的是master_test和slave_test两个库,两张库都有一张同样的表(偷懒,喜喜),表结构 表名 t_user | 字段名 | 类型 | 备注 | | :------: | :------: | :------: | | id | int | 主键自增ID | | name | varchar | 名称 | ![file](https://img2018.cnblogs.com/b

161920、使用Spring AOP实现MySQL数据库读写分离案例分析

一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库的主从配置,最简单的是一台Master和一台Slave(大型网站系统的话,当然会很复杂,这里只是分析了最简单的情况).通过主从配置主从数据库保持了相同的数据,我们在进行读操作的时候访问从数据库Slave,在进行写操作的时候访问主数据库Master.这样的话就减轻了一台服务器的压力. 在进行读写分离案

使用Spring AOP实现MySQL数据库读写分离案例分析

一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库的主从配置,最简单的是一台Master和一台Slave(大型网站系统的话,当然会很复杂,这里只是分析了最简单的情况).通过主从配置主从数据库保持了相同的数据,我们在进行读操作的时候访问从数据库Slave,在进行写操作的时候访问主数据库Master.这样的话就减轻了一台服务器的压力. 在进行读写分离案

新春好跑步,以及数据库“读写分离”的点滴考虑

新春的好日子: 小风吹来: 花一样的味道: 满满的幸福滋味. 迈开步子在宽敞的马路上跑步,步伐轻盈,多么美好的事情. 跑步总是枯燥的,只有奔跑奔跑: 跑步是孤独的,每个人的都有自己的节奏: 跑步的时候总爱瞎想,昨天和一些同学聊到了数据库的"读写分离". 在我有限的认识中,我一直认为数据库"读写分离",是为了提升数据库的瓶颈,因为数据库写总是相对比较少,而读取可能总是比较多,甚至高几个数量级. 比如一个电子商务网站,把某一个产品上架,可能一个月才需要写一次,但是每天都

【转】mysql数据库读写分离数据同步

转载请注明来源:mysql数据库读写分离数据同步 mysql数据库读写分离数据同步 我是用了两个xp(一个主的,一个从的)的系统测试成功的,linux系统我也做测试了,没有成功,不过我想我所遇到的问题是同一个问题,xp下的可以成功,linux下的应该也可以成功,稍候会测试,然后更新结果! PS:刚测试了下linux 可以同步成功,主服务器是xp,从服务器是centos,可以成功. 例: A机器 192.168.0.2 B机器 192.168.0.3 两个机器可以ping通,互相访问 先配置主服务