Mysql 读写分离插件简化版

一.原理

1.基于互联网背景,服务响应需要越来越快,从而衍生出读写分离,即让主数据库(master)处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库(slave)处理SELECT查询操作;

2.避免慢查询长期占用链接,导致插入时变慢;或者避免插入时过慢影响查询速度;

3.主数据库只做修改,从服务器只做查询,同时主服务器的修改需要同步到从服务器。

4.服务启动时,配置好主从数据源,执行方法时根据注解ReadOnly选择从库(读库)数据源,默认选择主库(修改)数据源。

二代码框架

1.工程结构

mysql读写分离插件代码结构

2.读数据库注解定义

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

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnly {

}

3.数据库名称本地线程池设置

public class DbContextHolder {

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

    public static void setDbContext(String dbName) {
        if (dbName == null || "".equals(dbName)) {
            throw new NullPointerException();
        }
        contextHolder.set(dbName);
    }

    public static String getDbContext() {
        return contextHolder.get();
    }

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

}

4.动态数据源选择类

public class RoutingDataSource extends AbstractRoutingDataSource {

    private static final Logger LOG = LoggerFactory.getLogger(DBRouterAop.class);

    @Override
    public DataSource determineTargetDataSource() {
        return super.determineTargetDataSource();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        String dbName = DbContextHolder.getDbContext();
        LOG.info("target database source is " + (dbName == null ? "default datasource" : dbName));
        return dbName;
    }
}

5.数据源配置类

@Configuration
public class DataSourceConfig {

    @Autowired
    @Qualifier("master")
    private DbProperties master;

    @Autowired
    @Qualifier("slave")
    private DbProperties slave;

    @Bean
    public RoutingDataSource routingDataSource() {

        RoutingDataSource routingDataSource = new RoutingDataSource();
        Map targetDataSources = new HashMap<>();
        //master
        DataSource masterDatasource = getDataSource(master);
        targetDataSources.put(DbType.MASTER.name(), masterDatasource);
        routingDataSource.setDefaultTargetDataSource(masterDatasource);

        //slave
        DataSource slaveDatasource = getDataSource(slave);
        targetDataSources.put(DbType.SLAVE.name(), slaveDatasource);

        routingDataSource.setTargetDataSources(targetDataSources);
        routingDataSource.afterPropertiesSet();

        return routingDataSource;
    }

    private DataSource getDataSource(DbProperties properties) {
        return new DriverManagerDataSource(properties.getUrl(), properties.getUsername(), properties.getPassword());
    }
}

6.切面选择方法执行时选择的数据源

@Aspect
@Component
public class DBRouterAop {

    @Around(value = "@annotation(readOnly)")
    public Object proceed(ProceedingJoinPoint pjp, ReadOnly readOnly) throws Throwable {
        try {
            DbContextHolder.setDbContext(DbType.SLAVE.name());
            Object result = pjp.proceed();
            return result;
        } finally {
            DbContextHolder.removeDbContext();
        }
    }
}

7.pom文件



    4.0.0

    org.example
    datasource-router-starter
    1.0-SNAPSHOT

    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.5.RELEASE
        
    
    

        
            org.springframework.boot
            spring-boot-starter
        

        
            org.springframework.boot
            spring-boot-configuration-processor
            true
        

        
            org.springframework.boot
            spring-boot-autoconfigure
        

        
            org.springframework.boot
            spring-boot-starter-aop
        

        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.1.4
        

        
            mysql
            mysql-connector-java
            5.1.34
        

        
            ch.qos.logback
            logback-core
            1.2.3
            provided
        

        
            ch.qos.logback
            logback-classic
            1.2.3
            provided
        

        
            com.google.code.gson
            gson
            2.7
            provided
        

    

    
        
            
                org.apache.maven.plugins
                maven-source-plugin
                3.0.1
                
                    true
                
                
                    
                        compile
                        
                            jar
                        
                    
                
            
        
    



三.测试验证

1.依赖读写分离插件

   
            org.example
            datasource-router-starter
            1.0-SNAPSHOT
   

2.配置数据源

server:
  port: 8081

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:/mybatis/mapper/*.xml
  type-aliases-package: com.example.test.infrastructure.po.User

# 数据库配置
db:
  master:
    url: jdbc:mysql://127.0.0.1:3306/master?useUnicode=true
    username: root
    password: root123
  slave:
    url: jdbc:mysql://127.0.0.1:3306/slave?useUnicode=true
    username: root
    password: root123

3.结果验证

1.查询时数据源选择的时从库

从库查询

2.写入时数据源选择主库

主库写入

你可能感兴趣的:(Mysql 读写分离插件简化版)