关于利用mycat结合springboot实现数据库的读写分离(动态切换数据源)个人笔记

关于mycat这个中间件,我就不多写了,网上褒贬不一。但是我们作为学习来说,是学的一个思维能力,动手能力,理解能力。这里做一下笔记,方便以后查看吧。

 

这里说一下我这边的环境:

数据库:mysql5.7以上

mycat:1.65

 

首先我们完成mysql的主从同步,这里就不说怎么完成的了,在之前文章里讲到过。

安装mycat也不多说了,大家可以去网上找教程什么的,都很方便。

 

安装完成之后,我们打开mycat路径里的conf配置文件目录,在里面我们要注意两个配置文件:

1.schema.xml   Mycat对应的物理数据库和数据库表的配置

2.server.xml   Mycat的配置文件,设置账号、参数等

我们这里要对这俩配置文件进行配置:

schema.xml:




   
   
       
   
   
   
        select user()
       
       
           
           
       

   


 

 不要管它的配置,直接把我这段内容覆盖进去即可。

这里大致说一下

mysql主库ip:192.168.1.133

mysql从库ip:192.168.1.132

mycat安装的服务器ip:192.168.1.133也就是安装在主库服务器下

server.xml:





   

   
   
        root
        mycat_zyx
   

   
   
        user
        mycat_zyx
        true
   

关于更多配置,这里就不写了,可以自行查询,我这么配,主要是为了完成集成mycat中间件来实现读写分离。

就这么简单,配置就完成了。我们进入mycat目录启动mycat即可

mycat目录启动mycat:./mycat start

关于是否启动成功,进入mycat的logs目录下查看wrapper.log。里面如果有successful就说明启动成功了。

实在不放心,我们可以利用navicat工具去外部连接mycat虚拟数据库去看看是否成功

关于利用mycat结合springboot实现数据库的读写分离(动态切换数据源)个人笔记_第1张图片

这里要注意一下,mycat的端口号为8066,如果连不上,10060报错,注意一下端口号是否开放,或者说是否关闭防火墙。

到此处,mycat全部配置结束了。我们进入下一步看如何结合springboot来实现动态数据源切换。

 

首先,我们在maven引入以下包,如果有了的,可以忽略,重点就是aop这个包:


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

        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            1.3.2
        

        
            mysql
            mysql-connector-java
            runtime
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            com.alibaba
            druid
            1.0.23
        

    

 

之后我们在springboot的yml配置文件里加入以下配置:

关于利用mycat结合springboot实现数据库的读写分离(动态切换数据源)个人笔记_第2张图片

这里的username和password对应的是你在server.xml里配置的用户名和密码

然后在config包里创建配置类:

DataSourceConfig.java

import javax.sql.DataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DataSourceConfig {

    // 创建可读数据源
    @Bean(name = "selectDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.select") // application.properteis中对应属性的前缀
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }

    // 创建可写数据源
    @Bean(name = "updateDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.update") // application.properteis中对应属性的前缀
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }

}

 DataSourceContextHolder.java

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
@Lazy(false)
public class DataSourceContextHolder {
    // 采用ThreadLocal 保存本地多数据源
    private static final ThreadLocal contextHolder = new ThreadLocal<>();

    // 设置数据源类型
    public static void setDbType(String dbType) {
        contextHolder.set(dbType);
    }

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

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

}

DynamicDataSource.java

 

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

//在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。

@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Autowired
    @Qualifier("selectDataSource")
    private DataSource selectDataSource;

    @Autowired
    @Qualifier("updateDataSource")
    private DataSource updateDataSource;

    /**
     * 这个是主要的方法,返回的是生效的数据源名称
     */
    @Override
    protected Object determineCurrentLookupKey() {
        System.out.println("DataSourceContextHolder:::" + DataSourceContextHolder.getDbType());
        return DataSourceContextHolder.getDbType();
    }

    /**
     * 配置数据源信息
     */
    @Override
    public void afterPropertiesSet() {
        Map map = new HashMap<>();
        map.put("selectDataSource", selectDataSource);
        map.put("updateDataSource", updateDataSource);
        setTargetDataSources(map);
        setDefaultTargetDataSource(updateDataSource);
        super.afterPropertiesSet();
    }
}

配置完成之后,我们利用springboot的aop技术,来完成动态数据源切换。

SwitchDataSourceAOP.java

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.zyx.db.config.DataSourceContextHolder;

// 使用AOP动态切换不同的数据源
@Aspect
@Component
@Lazy(false)
@Order(0) // Order设定AOP执行顺序 使之在数据库事务上先执行
public class SwitchDataSourceAOP {
    // 这里切到你的方法目录
    @Before("execution(* com.zyx.service.*.*(..))")
    public void process(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        if (methodName.startsWith("get") || methodName.startsWith("count") || methodName.startsWith("find")
                || methodName.startsWith("list") || methodName.startsWith("select") || methodName.startsWith("check")) {
            DataSourceContextHolder.setDbType("selectDataSource");
        } else {
            // 切换dataSource
            DataSourceContextHolder.setDbType("updateDataSource");
        }
    }
}

 我们利用aop拦截service方法前置名来拦截service方法进行动态数据源切换。

所以这个事提醒了我们编程要规范。方法名最好不要随意乱取,要根据一定的规范来命名。

 

到这里,就全部结束了,至于是否成功,可以写一个controller,service,dao来做个测试,这里就不放测试结果了。

注意service的方法名前缀,包地址要和SwitchDataSourceAOP.java里的@Before("execution(* com.zyx.service.*.*(..))")地址对应

至于验证过程,大可以把yml里的配置改一下,读写数据源都用那个mycat的读数据源,然后用service里的写数据操作。看看是否能写即可。

 

 

你可能感兴趣的:(springboot,mysql,mycat)