1、简介
    MyCAT是一款由阿里Cobar演变而来的用于支持数据库,读写分离、分表分库的分布式中间件。MyCAT支持Oracle、MSSQL、MYSQL、PG、DB2关系型数据库,同时也支持MongoDB等非关系型数据库。

    2、原理
    MyCAT原理MyCAT主要是通过对SQL的拦截,然后经过一定规则的分片解析、路由分析、读写分离分析、缓存分析等,然后将SQL发给后端真实的数据块,并将返回的结果做适当处理返回给客户端。
    **QQ图片20191105155619.jpg

    QQ图片20191105155608.jpg

    3、如何配置

    2019-11-05_161432.png

    1. <?xml version="1.0"?>
    2. <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
    3. <mycat:schema xmlns:mycat="http://io.mycat/">
    4. <!-- TESTDB1 是mycat的逻辑库名称,链接需要用的 -->
    5. <schema name="mycat_testdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"></schema>
    6. <!-- database 是MySQL数据库的库名 -->
    7. <dataNode name="dn1" dataHost="localhost1" database="test" />
    8. <!--
    9. dataNode节点中各属性说明:
    10. name:指定逻辑数据节点名称;
    11. dataHost:指定逻辑数据节点物理主机节点名称;
    12. database:指定物理主机节点上。如果一个节点上有多个库,可使用表达式db$0-99, 表示指定0-99这100个数据库;
    13. dataHost 节点中各属性说明:
    14. name:物理主机节点名称;
    15. maxCon:指定物理主机服务最大支持1000个连接;
    16. minCon:指定物理主机服务最小保持10个连接;
    17. writeType:指定写入类型;
    18. 0,只在writeHost节点写入;
    19. 1,在所有节点都写入。慎重开启,多节点写入顺序为默认写入根据配置顺序,第一个挂掉切换另一个;
    20. dbType:指定数据库类型;
    21. dbDriver:指定数据库驱动;
    22. balance:指定物理主机服务的负载模式。
    23. 0,不开启读写分离机制;
    24. 1,全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,S2都参与select语句的负载均衡;
    25. 2,所有的readHost与writeHost都参与select语句的负载均衡,也就是说,当系统的写操作压力不大的情况下,所有主机都可以承担负载均衡;
    26. -->
    27. <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
    28. <heartbeat>select user()</heartbeat>
    29. <!-- 可以配置多个主从 -->
    30. <writeHost host="hostM1" url="192.168.212.202:3306" user="root" password="root">
    31. <!-- 可以配置多个从库 -->
    32. <readHost host="hostS2" url="192.168.212.203:3306" user="root" password="root" />
    33. </writeHost>
    34. </dataHost>
    35. </mycat:schema>
    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!-- - - Licensed under the Apache License, Version 2.0 (the "License");
    3. - you may not use this file except in compliance with the License. - You
    4. may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
    5. - - Unless required by applicable law or agreed to in writing, software -
    6. distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
    7. WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
    8. License for the specific language governing permissions and - limitations
    9. under the License. -->
    10. <!DOCTYPE mycat:server SYSTEM "server.dtd">
    11. <mycat:server xmlns:mycat="http://io.mycat/">
    12. <!-- 读写都可用的用户 -->
    13. <user name="root" defaultAccount="true">
    14. <property name="password">123456</property>
    15. <property name="schemas">mycat_testdb</property>
    16. </user>
    17. <!-- 只读用户 -->
    18. <user name="user">
    19. <property name="password">user</property>
    20. <property name="schemas">mycat_testdb</property>
    21. <property name="readOnly">true</property>
    22. </user>
    23. </mycat:server>

    2019-11-05_161632.png

    3、SpringBoot整合Mycat实现动态数据源
    2019-11-05_162605.png

    QQ图片20191105162503.jpg

    QQ图片20191105162511.jpg

    1. spring:
    2. datasource:
    3. ###可读数据源
    4. select:
    5. jdbc-url: jdbc:mysql://192.168.212.205:8066/mycat_testdb
    6. driver-class-name: com.mysql.jdbc.Driver
    7. username: user
    8. password: user
    9. ####可写数据源
    10. update:
    11. jdbc-url: jdbc:mysql://192.168.212.205:8066/mycat_testdb
    12. driver-class-name: com.mysql.jdbc.Driver
    13. username: root
    14. password: 123456
    15. type: com.alibaba.druid.pool.DruidDataSource
    1. @Component
    2. @Lazy(false)
    3. public class DataSourceContextHolder {
    4. // 采用ThreadLocal 保存本地多数据源
    5. private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    6. // 设置数据源类型
    7. public static void setDbType(String dbType) {
    8. contextHolder.set(dbType);
    9. }
    10. public static String getDbType() {
    11. return contextHolder.get();
    12. }
    13. public static void clearDbType() {
    14. contextHolder.remove();
    15. }
    16. }


    1. @Configuration
    2. public class DataSourceConfig {
    3. // 创建可读数据源
    4. @Bean(name = "selectDataSource")
    5. @ConfigurationProperties(prefix = "spring.datasource.select") // application.properteis中对应属性的前缀
    6. public DataSource dataSource1() {
    7. return DataSourceBuilder.create().build();
    8. }
    9. // 创建可写数据源
    10. @Bean(name = "updateDataSource")
    11. @ConfigurationProperties(prefix = "spring.datasource.update") // application.properteis中对应属性的前缀
    12. public DataSource dataSource2() {
    13. return DataSourceBuilder.create().build();
    14. }
    15. }


    1. //在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。
    2. @Component
    3. @Primary
    4. public class DynamicDataSource extends AbstractRoutingDataSource {
    5. @Autowired
    6. @Qualifier("selectDataSource")
    7. private DataSource selectDataSource;
    8. @Autowired
    9. @Qualifier("updateDataSource")
    10. private DataSource updateDataSource;
    11. /**
    12. * 这个是主要的方法,返回的是生效的数据源名称
    13. */
    14. @Override
    15. protected Object determineCurrentLookupKey() {
    16. System.out.println("DataSourceContextHolder:::" + DataSourceContextHolder.getDbType());
    17. return DataSourceContextHolder.getDbType();
    18. }
    19. /**
    20. * 配置数据源信息
    21. */
    22. @Override
    23. public void afterPropertiesSet() {
    24. Map<Object, Object> map = new HashMap<>();
    25. map.put("selectDataSource", selectDataSource);
    26. map.put("updateDataSource", updateDataSource);
    27. setTargetDataSources(map);
    28. setDefaultTargetDataSource(updateDataSource);
    29. super.afterPropertiesSet();
    30. }
    31. }


    1. // 使用AOP动态切换不同的数据源
    2. @Aspect
    3. @Component
    4. @Lazy(false)
    5. @Order(0) // Order设定AOP执行顺序 使之在数据库事务上先执行
    6. public class SwitchDataSourceAOP {
    7. // 这里切到你的方法目录
    8. @Before("execution(* com.mayikt.service.*.*(..))")
    9. public void process(JoinPoint joinPoint) {
    10. String methodName = joinPoint.getSignature().getName();
    11. if (methodName.startsWith("get") || methodName.startsWith("count") || methodName.startsWith("find")
    12. || methodName.startsWith("list") || methodName.startsWith("select") || methodName.startsWith("check")) {
    13. DataSourceContextHolder.setDbType("selectDataSource");
    14. } else {
    15. // 切换dataSource
    16. DataSourceContextHolder.setDbType("updateDataSource");
    17. }
    18. }
    19. }


    12-24.pptx初始MyCat实现读写分离与动态数据源切换.zip

    schema.xml配置mycat虚拟数据库与真是的数据之间的映射关系,我们项目中配置的是Mycat中虚拟的数据库;
    server.xml配置mycat的用户信息,其中可以配置用户是否有写的权限,这样就可以根据在项目中根据需要读写不同的权限不同的方法通过切换数据源来实现;

    **