MyCat 是目前最流行的基于 java 语言编写的数据库中间件,是一个实现了 MySQL 协议的服务器,前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和命令行访问,而其后端可以用 MySQL 原生协议与多个 MySQL 服务器通信,也可以用 JDBC 协议与大多数主流数据库服务器通信,其核心功能是分库分表。配合数据库的主从模式还可实现读写分离。官方学习地址
MyCat2 已经可以使用,目前仅支持java8
垂直分库 就是微服务的形式,把一个服务单元拆到一个库中
垂直分表 把一个大表,字段多的表,拆分成多个小表,或按照查询逻辑拆分主要信息表或次要信息表
水平分库 把数据库集群,数据通过hash 或 取模 的方式散到你的数据库节点中
水平分表 只针对大表进行切分,按一定的逻辑进行切分
1.读写分离

2.数据分片,垂直拆分(分库)、水平拆分(分表)、垂直+水平拆分(分库分表)

3.多数据源整合

MyCat 的原理种最重要的一个动词时”拦截“,它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户

这种方式把数据库的分布式从代码中解耦出来,程序员察觉不出来后台使用MyCat还是MySQL
github 地址,这里要找的是打包过的文件下载,不要下载源码,除非你要看源码或改。
# 下载
wget http://dl.mycat.org.cn/1.6.7.6/20210730131311/Mycat-server-1.6.7.6-release-20210730131311-linux.tar.gz
#解压
tar -xvf Mycat-server-1.6.7.6-release-20210730131311-linux.tar.gz
# 移动到指定文件夹
mv mycat/ /opt/software/
启动
# 控制台启动,确认启动过程不会出错
bin/mycat console
# 后台启动
bin/mycat start
配置文件介绍:
1.schema.xml 定义逻辑库,表、分片节点等内容
2.rule.xml 定义分片规则
3.server.xml 定义用户以及系统相关变量,如端口等
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
修改 server.xml
<!-- 连接mycat的用户信息 -->
<user name="mycat" defaultAccount="true">
<!-- 密码 -->
<property name="password">123456</property>
<!-- 逻辑库名称 -->
<property name="schemas">TESTDB</property>
<!-- 默认逻辑库 -->
<property name="defaultSchema">TESTDB</property>
<!--No MyCAT Database selected 错误前会尝试使用该schema作为schema,不设置则为null,报错 -->
<!-- 表级 DML 权限设置 -->
<!--
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
-->
</user>
配置个基本的连接,以便登上去查库中的表
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 在server.xml中被指定的逻辑库 -->
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
</schema>
<!-- 对应schema中的 DataNode,database 是真正物理上的数据库 -->
<dataNode name="dn1" dataHost="host1" database="my_sql_test" />
<!-- name对应 dataNode 的 datatHost -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
</mycat:schema>
登录
# 登录运维管理窗口
mysql -u账号 -p密码 -P 9066 -h IP
# 查看数据库
show database;
# 查看命令
show @@help
# 登录数据窗口
mysql -u账号 -p密码 -P 8066 -h IP
# 如
mysql -umycat -p123456 -P8066 -h192.168.81.104 --default-auth=mysql_native_password
--default-auth=mysql_native_password 是因为 mycat 使用的是5.7以下的加密方式登录
本文这里使用二进制复制,其余复制可以参考我以前所写Mysql-8.0.2 主从复制(GTID)、Mysql-8.0.2 高可用MGR,建议可以先使用二进制方式。

修改 /etc/my.cnf
# 主服务器唯一ID
server-id=1
# 启用二进制日志
log-bin=mysql-bin
# 设置不要复制的数据库(可设置多个)
binlog-ignore-db=mysql
# binlog-ignore-db=information_schema
# 设置需要复制的数据库,不配置代表所有,但切记配置不要复制的库,建议基础库都不排除掉
binlog-do-db=test1
# 设置binlog格式
binlog_format=STATEMENT
binlog 日志有三种格式
server-id=2
# 启用中继日志
relay-log=mysql-relay
重启主机、从机服务
# 创建用户
CREATE USER 账号@'%' IDENTIFIED BY '密码';
# 授权
GRANT REPLICATION SLAVE ON *.* TO 账号@'%';
# 查看主机的状态
mysql> show master status;
+---------------+-----------+--------------+------------------+-----------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+-----------+--------------+------------------+-----------------------------------------------+
| binlog.000021 | 372357328 | test1 | mysql | |
+---------------+-----------+--------------+------------------+-----------------------------------------------+
建议做之前操作,可以把之前的主从配置信息干掉,也就清洁一下。
# 停止复制
stop slave;
# 重置复制信息
reset master;
开始配置
# 配置复制信息
CHANGE MASTER TO
MASTER_HOST = '192.168.81.104',
MASTER_PORT = 3306,
MASTER_USER = 'repl',
MASTER_PASSWORD = 'Repl@123',
MASTER_LOF_FILE='binlog.000021',
MASTER_LOF_POS=372357328;
# 开始复制
start slave;
# 查看从机状态
show slave status\G;
修改 schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 在server.xml中被指定的逻辑库 -->
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
</schema>
<!-- 对应schema中的 DataNode,database 是真正物理上的数据库 -->
<dataNode name="dn1" dataHost="host1" database="my_sql_test" />
<!-- name对应 dataNode 的 datatHost -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021">
<!-- 定义读主机 -->
<readHost host="hostS1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021" ></readHost>
</writeHost>
</dataHost>
</mycat:schema>
dataNode 的 database 属性,为MySQL 真实的数据库名称。
dataHost 的 balance 属性,通过此属性配置读写分离的类型
dataHost 的 writeType 属性:
writeType 重新启动后以切换后的为准,切换记录在配置文件中:dnindex.properties
dataHost 的 switchType 属性:
在以上的主配置中添加
# 在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates
# 表示自增长字段每次递增的量,指自己字段的起始值,其默认值是1,取值范围是1~65535(主要是区分M1,M2的自增)
auto-increment-increment=2
# 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1~65535
auto-increment-offset=1
和主1配置不同的是
server-id=3
# 表示自增长字段从哪个数开始,指字段一次递增多少,他的取值范围是1~65535
auto-increment-offset=2
两台主机都要创建一个复制用户并授权。
延用之前的从配置,但是注意 server-id 一定不一样,配置完成后需要执行以上从机步骤。关系为 S1->(复制)M1,S2->M2。
主1和主2相互执行命令
CHANGE MASTER TO
MASTER_HOST = '192.168.81.xxx',
MASTER_PORT = 3306,
MASTER_USER = 'repl',
MASTER_PASSWORD = 'Repl@123',
MASTER_LOF_FILE='binlog.xxxx',
MASTER_LOF_POS=xxxxx;
# 启动
start slave;
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 在server.xml中被指定的逻辑库 -->
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
</schema>
<!-- 对应schema中的 DataNode,database 是真正物理上的数据库 -->
<dataNode name="dn1" dataHost="host1" database="my_sql_test" />
<!-- name对应 dataNode 的 datatHost -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021">
<!-- 定义读主1从1机 -->
<readHost host="hostS1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021" ></readHost>
</writeHost>
<!-- 定义写主2机 -->
<writeHost host="hostM2" url="jdbc:mysql://192.168.81.106:3306" user="dev_fqr" password="Dev@fqr2021">
<!-- 定义读主2从2机 -->
<readHost host="hostS2" url="jdbc:mysql://192.168.81.107:3306" user="dev_fqr" password="Dev@fqr2021" ></readHost>
</writeHost>
</dataHost>
</mycat:schema>
垂直切分就是微服务的分库操作,如 用户表、积分表等在一个库,被划分为用户服务;订单表、明细表、订单快照表等在一个库中,被划分为订单服务。
修改schema.xml配置
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 在server.xml中被指定的逻辑库 -->
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
<!-- 配置表,所有对 customer 表的操作都会走 dn2 -->
<table name="customer" dataNode="dn2"></table>
</schema>
<!-- 对应schema中的 DataNode,database 是真正物理上的数据库 -->
<dataNode name="dn1" dataHost="host1" database="orders" />
<dataNode name="dn2" dataHost="host2" database="users" />
<!-- name对应 dataNode 的 datatHost -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
</mycat:schema>
table 标签的 name 属性,代表实际库中的表,对所有mycat里customer的操作都会走指定的 dataNode.
修改schema.xml文件
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 在server.xml中被指定的逻辑库 -->
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
<!-- 配置表 -->
<table name="customer" dataNode="dn2"></table>
<!-- 配置表 -->
<table name="orders" dataNode="dn1,dn3" rule="mod_rule"></table>
</schema>
<!-- 对应schema中的 DataNode,database 是真正物理上的数据库 -->
<dataNode name="dn1" dataHost="host1" database="orders" />
<dataNode name="dn3" dataHost="host3" database="orders" />
<dataNode name="dn2" dataHost="host2" database="users" />
<!-- name对应 dataNode 的 datatHost -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
<dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.106:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
</mycat:schema>
修改rule.xml文件
<!-- 分片规则 -->
<tableRule name="mod_rule">
<rule>
<!-- 指定分片的列 -->
<columns>customer_id</columns>
<!-- 指定分片算法,为function的name -->
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<!-- 具体的分片算法指定类 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- 数据节点,根据你要分片的数量(机器数量) -->
<property name="count">2</property>
</function>
tableRule 表规则,其中name属性就是 schema.xml table标签的 rule属性
orders 订单表已经进行分表操作了,和它关联的 orders_detail 订单详情表如何进行 join 查询?其实我们也要对 orders_detail 进行分片操作。

Mycat借鉴了NewSQL领域的新秀 Foundation DB 的设计思路,Foundation DB 创新性的提出了 Table Group 的概念,其将子表的存储位置依赖于主表,并且物理上紧邻存放,因此彻底解决了 JOIN 的效率和性能问题,根据这一思路,提出了基于 E-R 关系的数据分片策略,子表的记录与所关联的父表记录存放在同一个数据分片上。
修改 schema.xml 配置
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 在server.xml中被指定的逻辑库 -->
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
<!-- 配置表 -->
<table name="customer" dataNode="dn2"></table>
<!-- 配置表 -->
<table name="orders" dataNode="dn1,dn3" rule="mod_rule">
<!-- join表的name,该表的(primaryKey)主键,该表的(joinKey)外键,对应主表的(parentKey)ID -->
<childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
</table>
</schema>
<!-- 对应schema中的 DataNode,database 是真正物理上的数据库 -->
<dataNode name="dn1" dataHost="host1" database="orders" />
<dataNode name="dn3" dataHost="host3" database="orders" />
<dataNode name="dn2" dataHost="host2" database="users" />
<!-- name对应 dataNode 的 datatHost -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
<dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.106:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
</mycat:schema>
childTable 为要join的子表
在分片的情况下,当业务表因为规模而进行分片以后,业务表与这些附属的字典表之间的关联,就成了比较棘手的问题,考虑到字典表具有以下几个特性:
鉴于此,Mycat定义了一种特殊的表,称之为"全局表",全局表具有以下特性:
将字典或者符合字典特性的一些表定义为全局表,则从另外一个方面,很好的解决了数据JOIN的难题。通过全局表+基于E-R关系的分片策略,MyCat 可以满足 80%以上的企业应用开发。
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 在server.xml中被指定的逻辑库 -->
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
<!-- 配置表 -->
<table name="customer" dataNode="dn2"></table>
<!-- 配置表 -->
<table name="orders" dataNode="dn1,dn3" rule="mod_rule">
<!-- join表的name,该表的(primaryKey)主键,该表的(joinKey)外键,对应主表的(parentKey)ID -->
<childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
</table>
<!-- 全局表,name="表名" dataNode="指定节点" type="全局global" -->
<table name="dict_order_type" dataNode="dn1,dn2,dn3" type="global"></table>
</schema>
<!-- 对应schema中的 DataNode,database 是真正物理上的数据库 -->
<dataNode name="dn1" dataHost="host1" database="orders" />
<dataNode name="dn3" dataHost="host3" database="orders" />
<dataNode name="dn2" dataHost="host2" database="users" />
<!-- name对应 dataNode 的 datatHost -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
<dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.106:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1" slaveThreshold="100">
<!-- 心跳检测 -->
<heartbeat>select user()</heartbeat>
<!-- 定义写主1机 -->
<writeHost host="hostM1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
</dataHost>
</mycat:schema>
# 修改 schema.xml
<table name="orders" dataNode="dn1,dn3" rule="sharding_by_intfile"></table>
# 修改 rule.xml
<!-- 分片规则 -->
<tableRule name="mod_rule">
<rule>
<!-- 指定分片的列 -->
<columns>areacode</columns>
<!-- 指定分片算法,为function的name -->
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<!-- 具体的分片算法指定类 -->
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
<!-- 标识配置文件 -->
<property name="mapFile">partition-hash-int.txt</property>
<!-- type:0为int类型,非0为String类型 -->
<property name="type">1</property>
<!-- 默认节点:小于 0 表示不设置默认节点,大于等于0表示设置默认节点,
配置文件找不到枚举值,就让他路由到默认节点找,没有设置默认节点,在文件找不到,就报错 -->
<property name="defaultNode">0</property>
</function>
# 修改partition-hash-int.txt文件,添加如下
# 找到区域编号110的,认为是第1个数据节点(dn1)
110=0
# 找到区域编号120的,认为是第2个数据节点(dn3)
120=1
# 修改 schema.xml
<table name="payment_info" dataNode="dn1,dn2" rule="auto_sharding_long"></table>
# 修改 rule.xml
<!-- 分片规则 -->
<tableRule name="auto_sharding_long">
<rule>
<!-- 指定分片的列 -->
<columns>order_id</columns>
<!-- 指定分片算法,为function的name -->
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
<!-- 具体的分片算法指定类 -->
<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
<!-- 定义范围 -->
<property name="mapFile">autopartition-long.txt</property>
<!-- 不在范围找默认节点 -->
<property name="defaultNode">0</property>
</function>
# 修改autopartition-long.txt文件,不在配置文件默认找第0个节点(dn1)
# 0-102 到第1个节点(dn1)
0-102=0
# 103-200到第2个节点(dn2)
103-200=1
# 修改 schema.xml
<table name="login_info" dataNode="dn1,dn2" rule="sharding_by_date"></table>
# 修改 rule.xml
<!-- 分片规则 -->
<tableRule name="sharding_by_date">
<rule>
<!-- 指定分片的列 -->
<columns>create_time</columns>
<!-- 指定分片算法,为function的name -->
<algorithm>partbyday</algorithm>
</rule>
</tableRule>
<!-- 具体的分片算法指定类 -->
<function name="partbyday" class="io.mycat.route.function.PartitionByDate">
<!-- 格式化时间 -->
<property name="dateFormat">yyyy-MM-dd</property>
<!-- 开始日期 -->
<property name="sBeginDate">2021-01-01</property>
<!-- 结束日期,结束日期一定是 节点*分区天数,
也就是我2个节点,分区天数3,1-3号到dn1,3-6号到dn2,6-9号的话又分到dn1;
如果不设置结束日期,则6-9号要分到dn3,没有dn3则报错
-->
<property name="sEndDate">2021-01-31</property>
<!-- 分区天数 -->
<property name="sPartionDay">2</property>
</function>
在实现分库分表的情况下,数据库自增主键已无法保证自增主键的全局唯一,为此,Mycat 提供了全局的 sequence ,并且提供了包含本地配置和数据库配置等多种实现方式
此方式 Mycat 将 sequence 配置到文件中,当使用到 sequence 中的配置后,Mycat 会更下 classpath 中的sequence_conf.properties 文件中 sequence 当前的值
优点:本地加载,读取速度快
缺点:抗风险能力差,Mycat所在主机宕机后,无法读取本地文件。
全局序列 ID=64位二进制(42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))换算成十进制为18位的long类型,每秒可以并发12位二进制的累加。
优点:配置简单
缺点:18位ID过长
利用数据库一个表来进行技术累加。但是并不是每次生成序列都读写数据库,这样效率太低。Mycat 会预加载一部分号码段到 Mycat 的内存中,这样大部分读写序列都是在内存中完成的。如果内存中的号码段用完了 Mycat 会再向数据库要一次。
注意:
MYCAT_SEQUENCE 表和以下的 3 个function,需要放在同一个节点上。function请直接在具体节点的数据库上执行,如果执行的时候报:
you might want to use the less safe log_bin_trust_function_creators variable
需要对数据库做如下设置:
windows下my.ini[mysqld]加上log_bin_trust_function_creators=1
linux下/etc/my.cnf下my.ini[mysqld]加上log_bin_trust_function_creators=1
修改完后,即可在mysql数据库中执行下面的函数。
1. 创建全局序列表
CREATE TABLE MYCAT_SEQUENCE(
- sequence名称,最好为表名
name varchar(50) NOT NULL,
- 当前value,起始值
current_value INT NOT NULL,
- 增长步长! 可理解为mycat在数据库中一次读取多少个 sequence. 当这些用完后, 下次再从数据库中读取。
increment INT NOT NULL DEFAULT 100,
PRIMARY KEY(name)
)ENGINE=INNODB;
# 往表中插入数据
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('orders',1, 1000);
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('users',1, 1000);
2. 创建全局序列所需函数
- 获取当前sequence的值 (返回当前值,增量)
DROP FUNCTION IF EXISTS mycat_seq_currval;
DELIMITER
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf-8
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval=“-999999999,null”;
SELECT concat(CAST(current_value AS CHAR),“,”,CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;
RETURN retval;
END
DELIMITER;
- 设置sequence值
DROP FUNCTION IF EXISTS mycat_seq_setval;
DELIMITER
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS varchar(64) CHARSET utf-8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = value
WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END
DELIMITER;
– 获取下一个sequence值
DROP FUNCTION IF EXISTS mycat_seq_nextval;
DELIMITER
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf-8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END
DELIMITER;
3. sequence_db_conf.properties相关配置,指定sequence相关配置在哪个节点上
orders=dn1
users=dn1
4. server.xml配置:
<system>
<!-- 0本地文件 1数据库方式 2时间戳方式 -->
<property name="sequnceHandlerType">1</property>
</system>
5.插入数据
insert into orders(id,title,price) values(next value for MYCATSEQ_ORDERS,'手机','2000.00');
insert into (id,name) values(next value for MYCATSEQ_USERS,'张三');
我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel
文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co
我看到其他人也遇到过类似的问题,但没有一个解决方案对我有用。0.3.14gem与其他gem文件一起存在。我已经完全按照此处指示完成了所有操作:https://github.com/brianmario/mysql2.我仍然得到以下信息。我不知道为什么安装程序指示它找不到include目录,因为我已经检查过它存在。thread.h文件存在,但不在ruby目录中。相反,它在这里:C:\RailsInstaller\DevKit\lib\perl5\5.8\msys\CORE\我正在运行Windows7并尝试在Aptana3中构建我的Rails项目。我的Ruby是1.9.3。$gemin
我已经开始使用mysql2gem。我试图弄清楚一些基本的事情——其中之一是如何明确地执行事务(对于批处理操作,比如多个INSERT/UPDATE查询)。在旧的ruby-mysql中,这是我的方法:client=Mysql.real_connect(...)inserts=["INSERTINTO...","UPDATE..WHEREid=..",#etc]client.autocommit(false)inserts.eachdo|ins|beginclient.query(ins)rescue#handleerrorsorabortentirelyendendclient.commi
我的rails3.1.6应用程序中有一个自定义访问器方法,它为一个属性分配一个值,即使该值不存在。my_attr属性是一个序列化的哈希,除非为空白,否则应与给定值合并指定了值,在这种情况下,它将当前值设置为空值。(添加了检查以确保值是它们应该的值,但为简洁起见被删除,因为它们不是我的问题的一部分。)我的setter定义为:defmy_attr=(new_val)cur_val=read_attribute(:my_attr)#storecurrentvalue#makesureweareworkingwithahash,andresetvalueifablankvalueisgiven
我正在尝试绕过rails配置这个极其复杂的迷宫。到目前为止,我设法在ubuntu上设置了rvm(出于某种原因,ruby在ubuntu存储库中已经过时了)。我设法建立了一个Rails项目。我希望我的测试项目使用mysql而不是mysqlite。当我尝试“rakedb:migrate”时,出现错误:“!!!缺少mysql2gem。将其添加到您的Gemfile:gem'mysql2'”当我尝试“geminstallmysql”时,出现错误,告诉我需要为安装命令提供参数。但是,参数列表很大,我不知道该选择哪些。如何通过在ubuntu上运行的rvm和mysql获取rails3?谢谢。
有没有办法在liquidtemplate中输出(用于调试/信息目的)可用对象和对象属性??也就是说,假设我正在使用jekyll站点生成工具,并且我在我的index.html模板中(据我所知,这是一个液体模板)。它可能看起来像这样{%forpostinsite.posts%}{{post.date|date_to_string}}»{{post.title}}{%endfor%}是否有任何我可以使用的模板标签会告诉我/输出名为post的变量在此模板(以及其他模板)中可用。此外,是否有任何模板标签可以告诉我post对象具有键date、title、url、摘录、永久链接等
我尝试在我的应用中只使用:symbols作为关键词。我尝试在:symbol=>logic或string=>UI/languagespecific之间做出严格的决定但我也得到了每个JSON的一些“值”(即选项等),因为JSON中没有:symbols,所以我调用的所有哈希都具有“with_indifferent_access”属性。但是:数组是否有相同的东西?像那样a=['std','elliptic',:cubic].with_indifferent_accessa.include?:std=>true?编辑:将rails添加到标签 最佳答案
我进行了一些谷歌搜索,似乎缺少用于jRuby的IDE。我读过TextMate和Sublime,但它们不提供调试或代码完成功能。有人可以提出建议吗(或者这项技术还处于起步阶段)? 最佳答案 有几个选项;我更喜欢JetBrains'IntelliJ(RubyMine).AptanahasanEclipseplugin.NetBeansusedtohaveofficialsupport,不确定currentstate是什么是。 关于ruby-哪些IDE可用于jRuby?,我们在StackOve
我将guard与rspec和cucumber一起使用。要连续运行选定的规范,我只需使用focus标记来确定我要处理的内容。但问题是,如果没有带有该标签的规范,我想运行所有规范。我该怎么做?注意::我知道所有RSpec选项。因此,请仅在阅读问题后回复。 最佳答案 我通过以下配置实现了您描述的行为:#torunonlyspecificspecs,add:focustothespec#describe"foo",:focusdo#OR#it"shouldfoo",:focusdoconfig.treat_symbols_as_metada