分库
把对customer的操作分给dn2数据库,其他表的操作分发给dn1数据库。
首先配置schema.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?xml version="1.0"?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="TESTDB" checkSQLschema ="false" sqlMaxLimit ="100" dataNode ="dn1" > <table name ="customer" dataNode ="dn2" > </table > </schema > <dataNode name ="dn1" dataHost ="host1" database ="order" /> <dataNode name ="dn2" dataHost ="host2" database ="order" /> <dataHost name ="host1" maxCon ="1000" minCon ="10" balance ="0" writeType ="0" dbType ="mysql" dbDriver ="native" switchType ="1" slaveThreshold ="100" > <heartbeat > select user()</heartbeat > <writeHost host ="hostM1" url ="10.0.0.129:3306" user ="root" password ="kylin" > </writeHost > </dataHost > <dataHost name ="host2" maxCon ="1000" minCon ="10" balance ="0" writeType ="0" dbType ="mysql" dbDriver ="native" switchType ="1" slaveThreshold ="100" > <heartbeat > select user()</heartbeat > <writeHost host ="hostM2" url ="10.0.0.128:3306" user ="root" password ="kylin" > </writeHost > </dataHost > </mycat:schema >
由于我们配置了数据为order
所以分别在主从机上创建order数据库(自动复制数据配置的是mydb_kylin,其他需要自己创建)
CREATE DATABASE
order;
创建完成后,连接MyCat
mysql -u 用户名 -h 主机地址 -P 8066 -p
mysql -u mycat -h 10.0.0.128 -P 8066 -p
选择数据库,创建customer
1 2 3 4 5 6 CREATE TABLE customer( id INT auto_increment, NAME VARCHAR (200 ), PRIMARY KEY(id) );
运行成功,查看表所在位置。
成功分到我们所配置的表中。
接着创建其他表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #订单表 rows :600 万 CREATE TABLE orders( id INT auto_increment, order_type INT , customer_id INT , amount DECIMAL (10 ,2 ), PRIMARY KEY(id) ); #订单详细表 rows :600 万 CREATE TABLE orders_detail( id INT auto_increment, detail VARCHAR (200 ), order_id INT , PRIMARY key(id) ); #订单状态字典表 rows :20 CREATE TABLE dict_order_type( id int auto_increment, order_type VARCHAR (200 ), PRIMARY key(id) );
分库成功!!
水平分表 单表 首先修改schema.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?xml version="1.0"?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="TESTDB" checkSQLschema ="false" sqlMaxLimit ="100" dataNode ="dn1" > <table name ="customer" dataNode ="dn2" > </table > <table name ="orders" dataNode ="dn1,dn2" rule ="mod_rule" > </table > </schema > <dataNode name ="dn1" dataHost ="host1" database ="order" /> <dataNode name ="dn2" dataHost ="host2" database ="order" /> <dataHost name ="host1" maxCon ="1000" minCon ="10" balance ="0" writeType ="0" dbType ="mysql" dbDriver ="native" switchType ="1" slaveThreshold ="100" > <heartbeat > select user()</heartbeat > <writeHost host ="hostM1" url ="10.0.0.129:3306" user ="root" password ="kylin" > </writeHost > </dataHost > <dataHost name ="host2" maxCon ="1000" minCon ="10" balance ="0" writeType ="0" dbType ="mysql" dbDriver ="native" switchType ="1" slaveThreshold ="100" > <heartbeat > select user()</heartbeat > <writeHost host ="hostM2" url ="10.0.0.128:3306" user ="root" password ="kylin" > </writeHost > </dataHost > </mycat:schema >
接着配置规则rule.xml
配置修改完成后在我们的从机创建orders
表
1 2 3 4 5 6 7 CREATE TABLE orders( id INT auto_increment, order_type INT , customer_id INT , amount DECIMAL (10 ,2 ), PRIMARY KEY(id) );
接着启动mycat。
在创建一个命令窗口远程连接mycat。
1 2 3 4 5 6 insert into orders(id,order_type,customer_id,amount) values (1 ,101 ,100 ,100100 );INSERT INTO orders(id,order_type,customer_id,amount) VALUES (2 ,101 ,100 ,100300 );INSERT INTO orders(id,order_type,customer_id,amount) VALUES (3 ,101 ,101 ,120000 );INSERT INTO orders(id,order_type,customer_id,amount) VALUES (4 ,101 ,101 ,103000 );INSERT INTO orders(id,order_type,customer_id,amount) VALUES (5 ,102 ,101 ,100400 );INSERT INTO orders(id,order_type,customer_id,amount) VALUES (6 ,102 ,100 ,100020 );
运行插入语句。
注意这里insert语句不能省略字段名insert into orders values(xxxx),直接插入
查询一下select * from orders
这是因为345,126分别在我们配置的两个数据库中。mycat分别查询后拼接返回给我们。
虽然单表成功了,但是跟这个表相关的表怎么办?跨库join怎么办??
跨库join ER表 我们插入6条,跟orders表有关联的orders_detail
数据。
1 2 3 4 5 6 insert into orders_detail(id,detail,order_id) values (1 ,'detail1' ,1 );INSERT INTO orders_detail(id,detail,order_id) VALUES (2 ,'detail1' ,2 );INSERT INTO orders_detail(id,detail,order_id) VALUES (3 ,'detail1' ,3 );INSERT INTO orders_detail(id,detail,order_id) VALUES (4 ,'detail1' ,4 );INSERT INTO orders_detail(id,detail,order_id) VALUES (5 ,'detail1' ,5 );INSERT INTO orders_detail(id,detail,order_id) VALUES (6 ,'detail1' ,6 );
插入后我们运行查询语句
1 2 3 SELECT o.* ,od.detailFROM orders oINNER JOIN orders_detail od ON o.id = od.order_id;
这是因为当我们运行这条查询语句时,mycat将它拦截分别到我配置的主从机去运行查找与orders_detail
符合sql语句的查询结果。由于orders_detail
只存在我的主机上,所以只能查出3条(每台机器上只有3条orders记录),而从机上没有这张表直接返回报错(查出的3条数据不管了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <?xml version="1.0"?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="TESTDB" checkSQLschema ="false" sqlMaxLimit ="100" dataNode ="dn1" > <table name ="customer" dataNode ="dn2" > </table > <table name ="orders" dataNode ="dn1,dn2" rule ="mod_rule" > <childTable name ="orders_detail" primaryKey ="id" joinKey ="order_id" parentKey ="id" /> </table > </schema > <dataNode name ="dn1" dataHost ="host1" database ="order" /> <dataNode name ="dn2" dataHost ="host2" database ="order" /> <dataHost name ="host1" maxCon ="1000" minCon ="10" balance ="0" writeType ="0" dbType ="mysql" dbDriver ="native" switchType ="1" slaveThreshold ="100" > <heartbeat > select user()</heartbeat > <writeHost host ="hostM1" url ="10.0.0.129:3306" user ="root" password ="kylin" > </writeHost > </dataHost > <dataHost name ="host2" maxCon ="1000" minCon ="10" balance ="0" writeType ="0" dbType ="mysql" dbDriver ="native" switchType ="1" slaveThreshold ="100" > <heartbeat > select user()</heartbeat > <writeHost host ="hostM2" url ="10.0.0.128:3306" user ="root" password ="kylin" > </writeHost > </dataHost > </mycat:schema >
保存退出。删掉刚才orders_detail
添加的记录,在另一台机器从机上也创建该表orders_detail
1 2 3 4 5 6 CREATE TABLE orders_detail( id INT auto_increment, detail VARCHAR (200 ), order_id INT , PRIMARY key(id) );
启动mycat。
再次向orders_detail
表中添加数据
1 2 3 4 5 6 insert into orders_detail(id,detail,order_id) values (1 ,'detail1' ,1 );INSERT INTO orders_detail(id,detail,order_id) VALUES (2 ,'detail1' ,2 );INSERT INTO orders_detail(id,detail,order_id) VALUES (3 ,'detail1' ,3 );INSERT INTO orders_detail(id,detail,order_id) VALUES (4 ,'detail1' ,4 );INSERT INTO orders_detail(id,detail,order_id) VALUES (5 ,'detail1' ,5 );INSERT INTO orders_detail(id,detail,order_id) VALUES (6 ,'detail1' ,6 );
运行查询语句
1 2 3 SELECT o.* ,od.detailFROM orders oINNER JOIN orders_detail od ON o.id = od.order_id;
成功查询到。
分别插入并且规则与父表保持一致。
全局表 设定为全局的表,会直接复制给每个数据库一份,所有写操作也会同步给多个库。
所以全局表一般不能是大数据表或者更新频繁的表
一般是字典表或者系统表为宜。
这里的全局表是dict_order_type
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?xml version="1.0"?> <!DOCTYPE mycat :schema SYSTEM "schema.dtd" > <mycat:schema xmlns:mycat ="http://io.mycat/" > <schema name ="TESTDB" checkSQLschema ="false" sqlMaxLimit ="100" dataNode ="dn1" > <table name ="customer" dataNode ="dn2" > </table > <table name ="orders" dataNode ="dn1,dn2" rule ="mod_rule" > <childTable name ="orders_detail" primaryKey ="id" joinKey ="order_id" parentKey ="id" /> </table > <table name ="dict_order_type" dataNode ="dn1,dn2" type ="global" > </table > </schema > <dataNode name ="dn1" dataHost ="host1" database ="order" /> <dataNode name ="dn2" dataHost ="host2" database ="order" /> <dataHost name ="host1" maxCon ="1000" minCon ="10" balance ="0" writeType ="0" dbType ="mysql" dbDriver ="native" switchType ="1" slaveThreshold ="100" > <heartbeat > select user()</heartbeat > <writeHost host ="hostM1" url ="10.0.0.129:3306" user ="root" password ="kylin" > </writeHost > </dataHost > <dataHost name ="host2" maxCon ="1000" minCon ="10" balance ="0" writeType ="0" dbType ="mysql" dbDriver ="native" switchType ="1" slaveThreshold ="100" > <heartbeat > select user()</heartbeat > <writeHost host ="hostM2" url ="10.0.0.128:3306" user ="root" password ="kylin" > </writeHost > </dataHost > </mycat:schema >
接着在每个机器中创建dict_order_type
表
1 2 3 4 5 CREATE TABLE dict_order_type( id int auto_increment, order_type VARCHAR (200 ), PRIMARY key(id) );
启动mycat。连接mycat。插入数据
1 2 insert into dict_order_type(id,order_type) values (101 ,'type1' );INSERT INTO dict_order_type(id,order_type) VALUES (102 ,'type2' );
每个数据库中都插入了同样的数据。
全局序列 当我们分库分表之后id又是如何保持唯一呢??如果使用自增是不适合的会导致重复,所以就需要使用到全局序列来保持唯一。
(0)在mycat创建本地文件,插入时自增。(不推荐)
(2)时间戳方式虽然很好但是太长了18位。(不推荐)
(1)数据库方式 步长默认为100
建库序列脚本 首先在我们的主机上运行MYCAT_SEQUENCE
表
1 2 3 CREATE TABLE MYCAT_SEQUENCE (NAME VARCHAR (50 ) NOT NULL ,current_value INT NOT NULL ,increment INT NOT NULL DEFAULT 100 , PRIMARY KEY(NAME)) ENGINE= INNODB;
接着创建三个函数。
1 2 3 4 5 6 7 8 9 10 11 DELIMITER $$ CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR (50 )) RETURNS VARCHAR (64 )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 ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 DELIMITER $$ CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR (50 ),VALUE INTEGER ) RETURNS VARCHAR (64 )DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = VALUE WHERE NAME = seq_name;RETURN mycat_seq_currval(seq_name);END $$DELIMITER ; DELIMITER $$ CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR (50 )) RETURNS VARCHAR (64 )DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE NAME = seq_name;RETURN mycat_seq_currval(seq_name);END $$DELIMITER ;
接着我们往该序列表中添加数据。
1 2 INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES ('ORDERS' , 400000 , 100 );
修改配置文件 sequence_db_conf.properties
1 2 3 4 5 GLOBAL =dn1 COMPANY =dn1 CUSTOMER =dn1 ORDERS =dn1
编辑server.xml
修改为1
保存后重启mycat。连接mycat,插入语句
1 insert into `orders`(id,amount,customer_id,order_type) values (next value for MYCATSEQ_ORDERS ,1000 ,101 ,102 );
多次运行后查看表中的数据。
插入成功,全局序列设置成功。接着重启mycat。再次运行插入语句查看效果。
此时的序列号是从200开始的,所以它的步长为100。
当然也可以自主生成根据业务逻辑组合,例如可以利用 redis的单线程原子性 incr来生成序列。不过这样就需要在java代码中实现。