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

 

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

数据库:mysql5.7以上

mycat:1.65

 

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

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

 

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

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

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

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

schema.xml:

<?xml version="1.0"?>
 <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
 <mycat:schema xmlns:mycat="http://io.mycat/">
     <!-- TESTDB1 是mycat的逻辑库名称,链接需要用的 -->
     <schema name="mycat_zyx" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema>
         <!-- database 是MySQL数据库的库名 -->
     <dataNode name="dn1" dataHost="localhost1" database="zyx" />
     <!--


    上面的dataNode对应这里的dataNode的name,也就是dn1,这里相同即可,可以随便取名
    dataNode节点中各属性说明:
    name:指定逻辑数据节点名称;
    dataHost:指定逻辑数据节点物理主机节点名称;也就是下面的datahost的name,也就是localhost1对面下面的localhost1,这里相同即可
    database:指定物理主机节点上。如果一个节点上有多个库,可使用表达式db$0-99,     表示指定0-99这100个数据库;

    dataHost 节点中各属性说明:
        name:物理主机节点名称;
        maxCon:指定物理主机服务最大支持1000个连接;
        minCon:指定物理主机服务最小保持10个连接;
        writeType:指定写入类型;
            0,只在writeHost节点写入;
            1,在所有节点都写入。慎重开启,多节点写入顺序为默认写入根据配置顺序,第一个挂掉切换另一个;
        dbType:指定数据库类型;
        dbDriver:指定数据库驱动;
        balance:指定物理主机服务的负载模式。
            0,不开启读写分离机制;
            1,全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡;
            2,所有的readHost与writeHost都参与select语句的负载均衡,也就是说,当系统的写操作压力不大的情况下,所有主机都可以承担负载均衡;

-->
     <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
         <heartbeat>select user()</heartbeat>
         <!-- 可以配置多个主从 -->
         <writeHost host="hostM1" url="192.168.1.133:3306" user="root" password="root">
             <!-- 可以配置多个从库 -->
             <readHost host="hostS2" url="192.168.1.132:3306" user="root" password="root" />
         </writeHost>
     </dataHost>
 </mycat:schema>


 

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

这里大致说一下

mysql主库ip:192.168.1.133

mysql从库ip:192.168.1.132

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

server.xml:

<?xml version="1.0" encoding="UTF-8"?>
 <!-- - - Licensed under the Apache License, Version 2.0 (the "License"); 
     - you may not use this file except in compliance with the License. - You 
     may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 
     - - Unless required by applicable law or agreed to in writing, software - 
     distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT 
     WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the 
     License for the specific language governing permissions and - limitations 
     under the License. -->
 <!DOCTYPE mycat:server SYSTEM "server.dtd">
 <mycat:server xmlns:mycat="http://io.mycat/">
       <!-- 读写都可用的用户 -->
     <user name="root" defaultAccount="true">
         <property name="password">root</property>
         <property name="schemas">mycat_zyx</property>
     </user>    <!-- 只读用户 -->
     <user name="user">
         <property name="password">user</property>
         <property name="schemas">mycat_zyx</property>
         <property name="readOnly">true</property>
     </user></mycat:server>

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

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

mycat目录启动mycat:./mycat start

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

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

springboot配置mysql集群的yml springboot集成mycat_spring

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

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

 

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

<dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-aop</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
         <dependency>
             <groupId>org.mybatis.spring.boot</groupId>
             <artifactId>mybatis-spring-boot-starter</artifactId>
             <version>1.3.2</version>
         </dependency>        <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>        <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>druid</artifactId>
             <version>1.0.23</version>
         </dependency>
     </dependencies>

 

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

springboot配置mysql集群的yml springboot集成mycat_xml_02

这里的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<String> 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<Object, Object> 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里的写数据操作。看看是否能写即可。