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

springboot2.0+mybatis实现读写分离

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

springboot2.0+mybatis实现读写分离

一、application.yml配置文件

server:
  port: 8080
  servlet:
    context-path: /cm
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      master:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: username
        password: password
        url: jdbc:mysql://xxxxx:xxxx/test?autoReconnect=true&useCompression=true&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=GMT
        initial-size: 1
        min-idle: 1
        max-active: 50
        max-wait: 60000
      slave:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: xxxx
        password: xxxxxx
        url: jdbc:mysql://xxxx:xxxx/test?autoReconnect=true&useCompression=true&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=GMT
        initial-size: 1
        min-idle: 1
        max-active: 50
        max-wait: 60000
mybatis:
  mapper-locations: classpath:mapper
@Configuration
public class DataSourceConfig {

    @Value("${spring.datasource.type}")
    public Class dataSourceType;

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

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

    
    @Bean
    public DataSource routingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
                                          @Qualifier("slaveDataSource") DataSource slaveDataSource){
        Map targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceTypeEnum.master, masterDataSource);
        targetDataSources.put(DataSourceTypeEnum.slave, slaveDataSource);
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }
}

三、mybatis配置

package com.cm.server.busi.config;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.annotation.Resource;
import javax.sql.DataSource;


@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
@AutoConfigureAfter({ DataSourceConfig.class })
public class MybatisConfig {

    @Resource(name = "routingDataSource")
    private DataSource routingDataSource;

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(routingDataSource);
        // 下面的不可少,这个有了,就不用配置文件里的
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper
public class DynamicDataSource extends AbstractRoutingDataSource {


    
    @Override
    protected Object determineCurrentLookupKey() {
        return DatabaseContextHolder.getDatabaseType();
    }
}

五、通过ThreadLocal将数据源设置到每个线程上下文中

package com.cm.server.busi.config;

import com.cm.server.busi.enums.DataSourceTypeEnum;


public class DatabaseContextHolder {

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

    
    public static void setDatabaseType(DataSourceTypeEnum databaseType) {
        if (databaseType == null) {
            throw new NullPointerException();
        }
        contextHolder.set(databaseType);
    }

    
    public static DataSourceTypeEnum getDatabaseType() {
        return contextHolder.get() == null ? DataSourceTypeEnum.master : (DataSourceTypeEnum) contextHolder.get();
    }

    
    public static void clearDatabaseType() {
        contextHolder.remove();
    }
}

六、通过自动义注解,实现AOP拦截,达到切换数据源的目的。注:@EnableAspectJAutoProxy这个注解加上才能使自定义的注解生效

package com.cm.server.busi.annotation;

import com.cm.server.busi.config.DatabaseContextHolder;
import com.cm.server.busi.enums.DataSourceTypeEnum;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;


@Aspect
@Component
// 加了下面这个注解,自定义的标签才会生效
@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)
public class DataSourceAop {

    @Pointcut("@annotation(com.cm.server.busi.annotation.ReadDataSource) && execution(* com.cm.server.busi.service.impl..*.*(..))")
    public void readPointcut(){}
    @Pointcut("@annotation(com.cm.server.busi.annotation.MasterDataSource) && execution(* com.cm.server.busi.service.impl..*.*(..))")
    public void writePointcut(){}

    @Before("readPointcut()")
    public void readBefore(JoinPoint joinPoint) {
        DatabaseContextHolder.setDatabaseType(DataSourceTypeEnum.slave);
        System.out.println("USE DATASOURCE SLAVE");
    }

    @Before("writePointcut()")
    public void writeBefore(JoinPoint joinPoint) {
        DatabaseContextHolder.setDatabaseType(DataSourceTypeEnum.master);
        System.out.println("USE DATASOURCE MASTER");
    }

    @After("readPointcut() || writePointcut()")
    public void after() {
        DatabaseContextHolder.clearDatabaseType();
    }

}

访问只读库注解

package com.cm.server.busi.annotation;

import java.lang.annotation.*;


@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ReadDataSource {
}

访问读写库注解

package com.cm.server.busi.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MasterDataSource {
}

附上dataType枚举类

package com.cm.server.busi.enums;


public enum DataSourceTypeEnum {

    master,slave;
}

7、最后在业务层代码加上相应的注解即可

package com.cm.server.busi.service.impl;

import com.cm.server.busi.annotation.MasterDataSource;
import com.cm.server.busi.annotation.ReadDataSource;
import com.cm.server.busi.mapper.CmServerBusiMapper;
import com.cm.server.busi.model.DataVo;
import com.cm.server.busi.service.ICmServerBusiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;


@Service
public class CmServerBusiServiceImpl implements ICmServerBusiService {
    @Autowired
    private CmServerBusiMapper cmServerBusiMapper;

    @Override
    @ReadDataSource
    public Map selectDataInfo() {
        return cmServerBusiMapper.selectDataInfo();
    }

    @Override
    @MasterDataSource
    public void updateDataInfo(DataVo dataVo) {
        cmServerBusiMapper.updateDataInfo(dataVo);
    }
}

八、测试

 参考:SpringBoot+MyBatis+MySQL读写分离 - 废物大师兄 - 博客园

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

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

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