Java SpringBoot Mybatis Mycat

1、Mycat

下载

  1. wget http://dl.mycat.io/1.6.7.3/20190927161129/Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz

配置

server.xml,Mycat服务器配置,默认端口8066

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mycat:server SYSTEM "server.dtd">
  3. <mycat:server xmlns:mycat="http://io.mycat/">
  4. <system>
  5. <property name="useSqlStat">0</property>
  6. <property name="useGlobleTableCheck">0</property>
  7. <property name="sequnceHandlerType">2</property>
  8. <property name="handleDistributedTransactions">0</property>
  9. <property name="useOffHeapForMerge">1</property>
  10. <property name="memoryPageSize">1m</property>
  11. <property name="spillsFileBufferSize">1k</property>
  12. <property name="useStreamOutput">0</property>
  13. <property name="systemReserveMemorySize">384m</property>
  14. <property name="useZKSwitch">true</property>
  15. </system>
  16. <!--Mycat用户名-->
  17. <user name="root">
  18. <!--Mycat密码-->
  19. <property name="password">root</property>
  20. <!--Mycat数据库名-->
  21. <property name="schemas">mycat_test</property>
  22. </user>
  23. </mycat:server>

schema.xml,Mycat和Mysql节点映射配置

  1. <?xml version="1.0"?>
  2. <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
  3. <mycat:schema xmlns:mycat="http://io.mycat/">
  4. <!--Mycat数据库名-->
  5. <schema name="mycat_test" checkSQLschema="true" sqlMaxLimit="100">
  6. <!--Mycat表名,节点名称列表-->
  7. <table name="mycat_test_student" dataNode="dn1,dn2"/>
  8. </schema>
  9. <!--Mycat节点名称、节点地址、mysql数据库名-->
  10. <dataNode name="dn1" dataHost="localhost1" database="db01" />
  11. <dataNode name="dn2" dataHost="localhost1" database="db02" />
  12. <!--Mycat节点地址-->
  13. <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
  14. writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
  15. <heartbeat>select user()</heartbeat>
  16. <!-- mysql数据库服务器、账户、密码 -->
  17. <writeHost host="hostM1" url="192.168.1.71:3306" user="test"
  18. password="test@1234">
  19. </writeHost>
  20. </dataHost>
  21. </mycat:schema>

2、Spring Boot

数据源配置

  1. #mycat连接信息
  2. spring.datasource.url=jdbc:mysql://localhost:8066/mycat_test?serverTimezone=GMT
  3. spring.datasource.username=root
  4. spring.datasource.password=root
  5. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  6. #mybatis拦截器配置
  7. mybatis.config-location=classpath:mybatis.xml

Mybatis

mybatis.xml插件配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <settings>
  7. <!-- 打印查询语句 -->
  8. <setting name="logImpl" value="STDOUT_LOGGING" />
  9. </settings>
  10. <typeAliases>
  11. <typeAlias alias="TestPojo" type="xx.xx.TestPojo"/>
  12. </typeAliases>
  13. <!-- 拦截器插件,改写sql -->
  14. <plugins>
  15. <plugin interceptor="xx.interceptor.MyInterceptor">
  16. </plugin>
  17. </plugins>
  18. </configuration>

拦截器

  1. //拦截StatementHandler的prepare方法
  2. @Intercepts(value = {
  3. @Signature(type = StatementHandler.class,
  4. method = "prepare",
  5. args = {Connection.class,Integer.class})})
  6. public class MyInterceptor implements Interceptor {
  7. // 修改sql,添加前后缀
  8. private static final String preState="/*!mycat:datanode=";
  9. private static final String afterState="*/";
  10. @Override
  11. public Object intercept(Invocation invocation) throws Throwable {
  12. StatementHandler statementHandler=(StatementHandler)invocation.getTarget();
  13. MetaObject metaStatementHandler=SystemMetaObject.forObject(statementHandler);
  14. Object object=null;
  15. //分离代理对象链
  16. while(metaStatementHandler.hasGetter("h")){
  17. object=metaStatementHandler.getValue("h");
  18. metaStatementHandler=SystemMetaObject.forObject(object);
  19. }
  20. //获取sql
  21. String sql=(String)metaStatementHandler.getValue("delegate.boundSql.sql");
  22. //根据会话上下文,获取节点标识
  23. String node=(String) SessionUtil.getSession().getAttribute("appId");
  24. if(node!=null) {
  25. //重写sql,适配mycat
  26. sql = preState + node + afterState + sql;
  27. }
  28. System.out.println("sql is "+sql);
  29. metaStatementHandler.setValue("delegate.boundSql.sql",sql);
  30. Object result = invocation.proceed();
  31. System.out.println("Invocation.proceed()");
  32. return result;
  33. }
  34. // 返回当前拦截的对象(StatementHandler)的动态代理
  35. // 当拦截对象的方法被执行时, 动态代理中执行拦截器intercept方法.
  36. @Override
  37. public Object plugin(Object target) {
  38. return Plugin.wrap(target, this);
  39. }
  40. @Override
  41. public void setProperties(Properties properties) {
  42. String prop1 = properties.getProperty("prop1");
  43. String prop2 = properties.getProperty("prop2");
  44. System.out.println(prop1 + "------" + prop2);
  45. }
  46. }

总结

以上为关键实现,主要过程如下:

  • 搭建 Mycat 服务,设置提供的数据库信息
  • 配置Mycat动态映射的两个节点,Mycat根据sql语句中的/*!mycat:datanode=dn1*/进行动态切换数据源后执行sql
  • 配置 SpringBoot 的 Mycat 数据源连接
  • 配置 Mybatis 的拦截器插件
  • 配置 Mybatis 拦截器实现,根据上下文节点,改写 sql

    注意

  • 生产可采用Mycat集群,集群用ZK管理,以动态实例化数据源