ITPub博客

首页 > 数据库 > MySQL > 【Mycat】主键id自增长配置

【Mycat】主键id自增长配置

原创 MySQL 作者:小亮520cl 时间:2017-04-24 18:26:48 0 删除 编辑
在实现分库分表的情况下,数据库自增主键已无法保证自增主键的全局唯一。为此,MyCat 提供了全局sequence,并且提供了包含本地配置和数据库配置等多种实现方式,实现方式主要有三种:本地文件方式、数据库方式、本地时间戳算法。
本文主要介绍的是数据库的方式

1.看下配置文件如下:

  1. <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
  2.                 <!-- auto sharding by id (long) -->
  3.                 <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />  

  4.                 <table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
  5.             
  6.                 <table name="employee" primaryKey="ID" dataNode="dn1,dn2"
    1. rule="sharding-by-intfile" />

配置Server.xml
  1. <property name="sequnceHandlerType">1</property>



2、在其中一个分片点对应的数据库中创建表和存储过程

  1. 在121(dn1)上创建
  2. 1 创建sequence表
    1. CREATE TABLE `MYCAT_SEQUENCE` (
    2.   `name` varchar(50) NOT NULL,
    3.   `current_value` int(11) NOT NULL,
    4.   `increment` int(11) NOT NULL DEFAULT '100',
    5.   PRIMARY KEY (`name`)
    6. ) ENGINE=InnoDB    ====这是必备的三个字段,还可以加些别的字段
    2  获取下一个值
    1. DROP FUNCTION IF EXISTS `mycat_seq_nextval`;
    2. DELIMITER ;;
    3. CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET latin1
    4. DETERMINISTIC
    5. BEGIN
    6. UPDATE MYCAT_SEQUENCE
    7. SET current_value = current_value + increment WHERE name = seq_name;
    8. RETURN mycat_seq_currval(seq_name);
    9. END
    10. ;;
    11. DELIMITER ;
    3获取当前值
    1. DROP FUNCTION IF EXISTS `mycat_seq_currval`;
    2. DELIMITER ;;
    3. CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_currval`(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET latin1
    4. DETERMINISTIC
    5. BEGIN
    6. DECLARE retval VARCHAR(64);
    7. SET retval="-999999999,null";
    8. SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR) ) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;
    9. RETURN retval ;
    10. END
    11. ;;
    12. DELIMITER ;

    4 设置sequence值
    1. DROP FUNCTION IF EXISTS `mycat_seq_setval`;
    2. DELIMITER ;;
    3. CREATE DEFINER=`root`@`%` FUNCTION `mycat_seq_setval`(seq_name VARCHAR(50), value INTEGER) RETURNS varchar(64) CHARSET latin1
    4. DETERMINISTIC
    5. BEGIN
    6. UPDATE MYCAT_SEQUENCE
    7. SET current_value = value
    8. WHERE name = seq_name;
    9. RETURN mycat_seq_currval(seq_name);
    10. END
    11. ;;
    12. DELIMITER ; 

    5.插入初始数据
    1. INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('GLOBAL', 1, 10);
    2. INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('TRAVELRECORD', 1, 10);
    3. INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('EMPLOYEE', 1, 10);

  3. 6.设置 sequence_db_conf.properties
    1. [root@localhost conf]# more sequence_db_conf.properties
    2. #sequence stored in datanode
    3. GLOBAL=dn1
    4. COMPANY=dn1
    5. CUSTOMER=dn1
    6. ORDERS=dn1
    7. EMPLOYEE=dn1
    8. TRAVELRECORD=dn1     ----需要配置在该文件中并指定数据节点,一定要大写
    9. TT2=dn1

  4. 7.重启mycat 或reload


3 测试

  1. 全局表 唯一表:

  1. mysql> insert into company(name) values ('auto_test');
    Query OK, 1 row affected (1.08 sec)


    mysql> insert into company(name) values ('auto_test');
    Query OK, 1 row affected (0.45 sec)


    mysql> select * from company;
    +----+--------------------+
    | id | name               |
    +----+--------------------+
    |  1 | this is 119:3307   |
    |  9 | this is writeeeeee |
    | 10 | auto test          |
    | 11 | auto test          |
    | 12 | auto test          |
    | 13 | auto test          |
    | 14 | auto test          |
    | 15 | terwrw             |
    | 16 | auto_test          |
    | 17 | auto_test          |
    +----+--------------------+
    10 rows in set (0.16 sec)

  2. ####全局表和唯一表是可以直接插入的,不需要指定id,和单实例无差异

  1. 分片表:

  1. mysql> show create table employee\G;
  2. *************************** 1. row ***************************
  3.        Table: employee
  4. Create Table: CREATE TABLE `employee` (
  5.   `id` int(11) NOT NULL AUTO_INCREMENT,
  6.   `name` varchar(20) DEFAULT NULL,
  7.   `sharding_id` int(11) NOT NULL,
  8.   PRIMARY KEY (`id`)
  9. ) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=latin1
  10. 1 row in set (0.19 sec)


mysql> insert into employee(id,name,sharding_id) values (next value for MYCATSEQ_EMPLOYEE,'zs2',10000);    --插入第一条后
Query OK, 1 row affected (0.00 sec)

mysql> select * from MYCAT_SEQUENCE;                                                                       ----起始值变为11,此时第一条id也为11=1+10
+---------------+---------------+-----------+
| name          | current_value | increment |
+---------------+---------------+-----------+
| EMPLOYEE      |            11 |        10 |
| GLOBAL        |             1 |        10 |
| TRAVELRECORD  |             1 |        10 |
| TT2           |            30 |        10 |
+---------------+---------------+-----------+


再连续插入9条,上面的数据不变,当插入到第10条时,即自增id>11+10 时,上面会变成
mysql> select * from MYCAT_SEQUENCE;
+---------------+---------------+-----------+
| name          | current_value | increment |
+---------------+---------------+-----------+
| EMPLOYEE      |            21 |        10 |
| GLOBAL        |             1 |        10 |
| TRAVELRECORD  |             1 |        10 |
| TT2           |            30 |        10 |
+---------------+---------------+-----------+
3 rows in set (0.00 sec)


mysql> select * from employee;
+----+------+-------------+
| id | name | sharding_id |
+----+------+-------------+
| 11 | zs2  |       10000 |
| 12 | zs2  |       10000 |
| 13 | zs2  |       10000 |
| 14 | zs2  |       10000 |
| 15 | zs2  |       10000 |
| 16 | zs2  |       10000 |
| 17 | zs2  |       10000 |
| 18 | zs2  |       10000 |
| 19 | zs2  |       10000 |
| 20 | zs2  |       10000 |
| 21 | zs2  |       10000 |
| 22 | zs2  |       10000 |
| 23 | zs2  |       10000 |
+----+------+-------------+
13 rows in set (0.00 sec)



如果自增id不是分表的依据字段,也可以以这种方式插入

mysql> insert into employee(name,sharding_id) values ('zs2',10000);
Query OK, 1 row affected (0.00 sec)
但是这种方式会出现问题:
  1. mysql> insert into employee(name,sharding_id) values ('123',10000),('123',10000),('123',10010),('123',10010);
    Query OK, 4 rows affected (0.02 sec)
    Records: 2  Duplicates: 0  Warnings: 0


    mysql> select * from employee;
    +----+------+-------------+
    | id | name | sharding_id |
    +----+------+-------------+
    |  1 | 123  |       10010 |
    |  2 | 123  |       10010 |    --id在各自的分片上不冲突,但是合在一起会有重复,自增id不是全局的
    |  1 | 123  |       10000 |
    |  2 | 123  |       10000 |
    +----+------+-------------+


解决办法:不要忽略主键id,使用next value for MYCATSEQ_EMPLOYEE替
如果自增id是分片表的依据字段,那也是不能省略的:
mysql> insert into travelrecord(name) values ('auto_test');
ERROR 1064 (HY000): bad insert sql (sharding column:ID not provided,INSERT INTO travelrecord (name)
VALUES ('auto_test')




但是在程序层不可能使用next value for MYCATSEQ_EMPLOYEE 或者分片表每次都指定id吧,那就把自增id配成全局的!如下:
  1. <table name="travelrecord" primaryKey="ID" dataNode="dn1,dn2,dn3" autoIncrement="true" rule="auto-sharding-long" />
  2.  <table name="tt2" primaryKey="id" autoIncrement="true" dataNode="dn1,dn2,dn3" rule="mod-long" />
  3.  autoIncrement="true" rule="sharding-by-intfile" />    ###增加autoincrement属性




  4. 测试:
    mysql> insert into travelrecord(name) values ('123'),('123'),('123');
    Query OK, 1 row affected (0.63 sec)


    mysql> insert into employee(name,sharding_id) values ('123',10000),('123',10000),('123',10010),('123',10010);
    Query OK, 1 row affected (0.12 sec)


    mysql> insert into tt2(nm) values (99),(100),(101),(102);


    mysql> select * from employee;
    +----+------+-------------+
    | id | name | sharding_id |
    +----+------+-------------+
    | 91 | 123  |       10000 |
    | 92 | 123  |       10000 |
    | 93 | 123  |       10010 |
    | 94 | 123  |       10010 |
    +----+------+-------------+
    4 rows in set (0.01 sec)


    mysql> select * from travelrecord;
    +----+------+
    | id | name |
    +----+------+
    | 51 | 123  |
    | 52 | 123  |
    | 53 | 123  |
    +----+------+
    3 rows in set (0.01 sec)


    mysql> select * from tt2;
    +----+-----+
    | id | nm  |
    +----+-----+
    | 30 |  99 |
    | 33 | 102 |
    | 31 | 100 |
    | 32 | 101 |
    +----+-----+
    4 rows in set (0.38 sec)



    注意:mycat_sequence知识帮你获取非相同的主键id,如果你非要插入一个相同的主键id,但是处于不同的分片上,那是可以的!如:
      mysql> insert into employee(id,name,sharding_id) values (91,'123',10010);
      Query OK, 1 row affected (0.12 sec)
        mysql> select * from employee;
        +----+------+-------------+
        | id | name | sharding_id |
        +----+------+-------------+
        | 91 | 123  |       10000 |
        | 92 | 123  |       10000 |
        | 93 | 123  |       10010 |
        | 94 | 123  |       10010 |
        | 91 | 123  |       10010 |
        +----+------+-------------+
        4 rows in set (0.01 sec)





    总结如下:
    最开始的id=current_value+increment,继续插入时如果id一直<第二次的current_value+increment,current_value不会变,直到自增id 超过,然后current_value变为current_value+increment,以此类推

    参考:
    http://www.cnblogs.com/raphael5200/p/5900007.html
    https://github.com/yujiahui/Mycat-doc/blob/master/MyCAT自增字段和返回生成的主键ID的经验分享 
    <table name="employee" primarykey="ID" datanode="dn1,dn2"

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29096438/viewspace-2137902/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
毕业以后专业任职数据库工程师职位,itpub一直作为自己的笔记记录的地方,blog写的不详细,草书笔记,仅供参考!

注册时间:2013-09-12

  • 博文量
    529
  • 访问量
    1126951