当前位置:网站首页>Nine kinds of distributed primary key ID generation schemes of sub database and sub table are quite comprehensive

Nine kinds of distributed primary key ID generation schemes of sub database and sub table are quite comprehensive

2020-11-09 18:09:10 InfoQ

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/AUvcsschhqrhKopM5-XeMA","title":""},"content":[{"type":"text","text":"《sharding-jdbc Sub database and sub table 4 Seed fragmentation strategy 》"}]},{"type":"text","text":" We introduced "},{"type":"codeinline","content":[{"type":"text","text":"sharding-jdbc"}]},{"type":"text","text":" 4 The usage scenarios of the fragmentation strategy , Can meet the basic fragmentation function development , Let's look at the sub database table , How to generate a globally unique primary key for a partitioned table "},{"type":"codeinline","content":[{"type":"text","text":"ID"}]},{"type":"text","text":"."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" There are risks in introducing any technology , Database and table are no exception , Unless the library 、 The amount of table data continues to increase , To a certain extent , As a result, the existing high availability architecture has been unable to support , Otherwise, we do not recommend that we do the sub database table , Because after slicing the data , You'll find yourself on a path of stepping into a pit , And distributed primary keys "},{"type":"codeinline","content":[{"type":"text","text":"ID"}]},{"type":"text","text":" It's the first pit that we met ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" It is a difficult problem to generate a global unique primary key between different data nodes , A logic table "},{"type":"codeinline","content":[{"type":"text","text":"t_order"}]},{"type":"text","text":" Split into multiple real tables "},{"type":"codeinline","content":[{"type":"text","text":"t_order_n"}]},{"type":"text","text":", And then it's distributed to different libraries "},{"type":"codeinline","content":[{"type":"text","text":"db_0"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"db_1"}]},{"type":"text","text":"... , Since the auto increment keys of the real tables cannot be perceived by each other, they will produce duplicate primary keys , At this time, the database itself adds its own primary key , It can't meet the requirement of global uniqueness of primary key in sub database and sub table ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" db_0--\n |-- t_order_0\n |-- t_order_1\n |-- t_order_2\n db_1--\n |-- t_order_0\n |-- t_order_1\n |-- t_order_2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Although we can be strictly bound , Each partition table automatically increases the primary key "},{"type":"codeinline","content":[{"type":"text","text":" Initial value "}]},{"type":"text","text":" and "},{"type":"codeinline","content":[{"type":"text","text":" step "}]},{"type":"text","text":" To solve the problem "},{"type":"codeinline","content":[{"type":"text","text":"ID"}]},{"type":"text","text":" Repetitive questions , But this will make the operation and maintenance cost increase sharply , And the scalability is very poor , Once you want to expand the number of split tables , The data in the original table changed a lot , So it's not very desirable ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" step step = The number of separate sheets \n\n db_0--\n |-- t_order_0 ID: 0、6、12、18...\n |-- t_order_1 ID: 1、7、13、19...\n |-- t_order_2 ID: 2、8、14、20...\n db_1--\n |-- t_order_0 ID: 3、9、15、21...\n |-- t_order_1 ID: 4、10、16、22...\n |-- t_order_2 ID: 5、11、17、23..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" There are many third-party solutions that can solve this problem perfectly , For example, based on "},{"type":"codeinline","content":[{"type":"text","text":"UUID"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"SNOWFLAKE"}]},{"type":"text","text":" Algorithm 、"},{"type":"codeinline","content":[{"type":"text","text":"segment"}]},{"type":"text","text":" Paragraph number , Generate non repeating keys using a specific algorithm , Or directly reference the primary key generation service , Like the US regiment ("},{"type":"codeinline","content":[{"type":"text","text":"Leaf"}]},{"type":"text","text":") and sound of dripping water ("},{"type":"codeinline","content":[{"type":"text","text":"TinyId"}]},{"type":"text","text":") etc. ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" and "},{"type":"codeinline","content":[{"type":"text","text":"sharding-jdbc"}]},{"type":"text","text":" Two distributed primary key generation schemes are built in ,"},{"type":"codeinline","content":[{"type":"text","text":"UUID"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"SNOWFLAKE"}]},{"type":"text","text":", Not only that, it also takes away the interface of the distributed primary key generator , In order to facilitate developers to implement a custom primary key generator , In the future, we will connect to the custom generator sound of dripping water ("},{"type":"codeinline","content":[{"type":"text","text":"TinyId"}]},{"type":"text","text":") Primary key generation service for ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" As mentioned earlier in sharding-jdbc To automatically generate a primary key for a field ID, Only need "},{"type":"codeinline","content":[{"type":"text","text":"application.properties"}]},{"type":"text","text":" Do the following configuration in the file :"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"# Primary key field \nspring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id\n# Primary key ID Generation scheme \nspring.shardingsphere.sharding.tables.t_order.key-generator.type=UUID\n# Work the machine id\nspring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"key-generator.column"}]},{"type":"text","text":" Represents the primary key field ,"},{"type":"codeinline","content":[{"type":"text","text":"key-generator.type"}]},{"type":"text","text":" Primary key ID Generation scheme ( Built in or custom ),"},{"type":"codeinline","content":[{"type":"text","text":"key-generator.props.worker.id"}]},{"type":"text","text":" For the machine ID, Set the primary key generation scheme to "},{"type":"codeinline","content":[{"type":"text","text":"SNOWFLAKE"}]},{"type":"text","text":" Time machine ID Will participate in bit operations ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"> In the use of sharding-jdbc Two things should be noticed when distributed primary key is distributed :"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" once "},{"type":"codeinline","content":[{"type":"text","text":"insert"}]},{"type":"text","text":" The primary key field in the entity object of the insert operation has been assigned , Then even if the primary key generation scheme is configured, it will fail , Last SQL The data executed will be based on the value assigned ."}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Don't set auto increment attribute to primary key field , Otherwise, the primary key ID By default "},{"type":"codeinline","content":[{"type":"text","text":"SNOWFLAKE"}]},{"type":"text","text":" How to generate . such as : use "},{"type":"codeinline","content":[{"type":"text","text":"mybatis plus"}]},{"type":"text","text":" Of "},{"type":"codeinline","content":[{"type":"text","text":"@TableId"}]},{"type":"text","text":" Annotate fields "},{"type":"codeinline","content":[{"type":"text","text":"order_id"}]},{"type":"text","text":" Auto increment primary key is set , What kind of solution to configure at this time , Always follow the snowflake algorithm ."}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Let's analyze it from source sharding-jdbc Built in primary key generation scheme "},{"type":"codeinline","content":[{"type":"text","text":"UUID"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"SNOWFLAKE"}]},{"type":"text","text":" How did it happen ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"UUID"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" open "},{"type":"codeinline","content":[{"type":"text","text":"UUID"}]},{"type":"text","text":" The primary key of type generates the implementation class "},{"type":"codeinline","content":[{"type":"text","text":"UUIDShardingKeyGenerator"}]},{"type":"text","text":" Source code discovery for , Its generation rules are only "},{"type":"codeinline","content":[{"type":"text","text":"UUID.randomUUID()"}]},{"type":"text","text":" Such a line of code , forehead ~ There is a word in my heart "},{"type":"text","marks":[{"type":"strong"}],"text":" Oh my god "},{"type":"text","text":"."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"UUID Although we can achieve global uniqueness , But it is still not recommended as a primary key , Because we do business in real life, whether it is "},{"type":"codeinline","content":[{"type":"text","text":"user_id"}]},{"type":"text","text":" still "},{"type":"codeinline","content":[{"type":"text","text":"order_id"}]},{"type":"text","text":" Primary keys are mostly integers , and UUID It's a 32 Bit string ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Its storage and query to "},{"type":"codeinline","content":[{"type":"text","text":"MySQL"}]},{"type":"text","text":" High performance consumption , and "},{"type":"codeinline","content":[{"type":"text","text":"MySQL"}]},{"type":"text","text":" Officials have also made clear their recommendations , The primary key should be as short as possible , As a database primary key UUID The disorder of the data also leads to frequent changes in data locations , Seriously affect performance ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"public final class UUIDShardingKeyGenerator implements ShardingKeyGenerator {\n private Properties properties = new Properties();\n\n public UUIDShardingKeyGenerator() {\n }\n\n public String getType() {\n return \"UUID\";\n }\n\n public synchronized Comparable generateKey() {\n return UUID.randomUUID().toString().replaceAll(\"-\", \"\");\n }\n\n public Properties getProperties() {\n return this.properties;\n }\n\n public void setProperties(Properties properties) {\n this.properties = properties;\n }\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"SNOWFLAKE"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"SNOWFLAKE"}]},{"type":"text","text":"( Snowflake algorithm ) Is the default primary key generation scheme , Generate a 64bit Long integer ("},{"type":"codeinline","content":[{"type":"text","text":"Long"}]},{"type":"text","text":") data ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"sharding-jdbc"}]},{"type":"text","text":" The primary key generated by snowflake algorithm is mainly composed of 4 Part of it is made up of ,"},{"type":"codeinline","content":[{"type":"text","text":"1bit"}]},{"type":"text","text":" Sign bit 、"},{"type":"codeinline","content":[{"type":"text","text":"41bit"}]},{"type":"text","text":" Time stamp bit 、"},{"type":"codeinline","content":[{"type":"text","text":"10bit"}]},{"type":"text","text":" Working process bit and "},{"type":"codeinline","content":[{"type":"text","text":"12bit"}]},{"type":"text","text":" Serial number position . "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/84/84b9668edec202a384f320e51b1939fd.png","alt":" Snowflake algorithm ID form ","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":" Sign bit (1bit position )"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java in Long The highest bit of a type is the sign bit , A positive number is 0, Negative number is 1, General generation ID All positive , So the default is 0"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":" Time stamp bit (41bit) "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"41 The number of milliseconds a bit's timestamp can hold is 2 Of 41 The next power , And the total number of milliseconds a year is "},{"type":"codeinline","content":[{"type":"text","text":"1000L * 60 * 60 * 24 * 365"}]},{"type":"text","text":", The calculation time is about 69 year , forehead ~, I have enough for my life ."}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"Math.pow(2, 41) / (365 * 24 * 60 * 60 * 1000L) = = 69 year "}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":" Work progress bit (10bit) "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Represents a unique work process id, The default value is 0, It can be done by "},{"type":"codeinline","content":[{"type":"text","text":"key-generator.props.worker.id"}]},{"type":"text","text":" Property settings ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=0000"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":" Serial number position (12bit) "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Different... Are generated in the same millisecond ID."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":" Clock back "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Understand the primary key of snowflake algorithm ID It's not hard to find out , This is an algorithm that depends heavily on server time , And those who rely on server time will encounter a thorny problem :"},{"type":"codeinline","content":[{"type":"text","text":" Clock back "}]},{"type":"text","text":"."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":" Why is there a clock back ?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" There is a network time protocol in the Internet "},{"type":"codeinline","content":[{"type":"text","text":"ntp"}]},{"type":"text","text":" Full name ("},{"type":"codeinline","content":[{"type":"text","text":"Network Time Protocol"}]},{"type":"text","text":") , Specifically used to synchronize 、 Calibrate the time of each computer in the network ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" That's why , Our phones don't have to manually calibrate the time now , But everyone's cell phone time is the same ."}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Our hardware clock may become inaccurate for various reasons ( "},{"type":"codeinline","content":[{"type":"text","text":" fast "}]},{"type":"text","text":" or "},{"type":"codeinline","content":[{"type":"text","text":" slow "}]},{"type":"text","text":" ), At this point, we need "},{"type":"codeinline","content":[{"type":"text","text":"ntp"}]},{"type":"text","text":" Service to do time calibration , When you do the calibration, the server clock will happen "},{"type":"codeinline","content":[{"type":"text","text":" jumping "}]},{"type":"text","text":" perhaps "},{"type":"codeinline","content":[{"type":"text","text":" Back to dial the "}]},{"type":"text","text":" The problem of ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":" How to solve clock callback by snowflake algorithm "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Server clock callback can cause duplicate ID,"},{"type":"codeinline","content":[{"type":"text","text":"SNOWFLAKE"}]},{"type":"text","text":" In the scheme, the original snowflake algorithm is improved , Added a maximum tolerated clock callback in milliseconds ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" If the time of clock callback exceeds the maximum tolerance threshold of milliseconds , The program reports an error directly ; If it's within tolerance , Default distributed primary key generator , It will wait for the clock to synchronize to the time of the last primary key generation before continuing to work ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Maximum number of clock callback milliseconds tolerated , The default value is 0, You can use the properties "},{"type":"codeinline","content":[{"type":"text","text":"max.tolerate.time.difference.milliseconds"}]},{"type":"text","text":" Set up ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"# Maximum number of clock callback milliseconds tolerated \nspring.shardingsphere.sharding.tables.t_order.key-generator.max.tolerate.time.difference.milliseconds=5"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Here is the source code implementation class "},{"type":"codeinline","content":[{"type":"text","text":"SnowflakeShardingKeyGenerator"}]},{"type":"text","text":", The core process is as follows :"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" When the primary key was last generated "},{"type":"codeinline","content":[{"type":"text","text":"lastMilliseconds"}]},{"type":"text","text":" And current time "},{"type":"codeinline","content":[{"type":"text","text":"currentMilliseconds"}]},{"type":"text","text":" compare , If "},{"type":"codeinline","content":[{"type":"text","text":"lastMilliseconds"}]},{"type":"text","text":" > "},{"type":"codeinline","content":[{"type":"text","text":"currentMilliseconds"}]},{"type":"text","text":" It means that the clock is back ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Then judge the difference between the two times ("},{"type":"codeinline","content":[{"type":"text","text":"timeDifferenceMilliseconds"}]},{"type":"text","text":") Whether the maximum tolerance time threshold is set "},{"type":"codeinline","content":[{"type":"text","text":"max.tolerate.time.difference.milliseconds"}]},{"type":"text","text":" Inside , The thread sleep difference time is within the threshold value "},{"type":"codeinline","content":[{"type":"text","text":"Thread.sleep(timeDifferenceMilliseconds)"}]},{"type":"text","text":", Otherwise, if it is greater than the difference value, it will report an exception directly ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":" \n/**\n * @author xiaofu\n */\npublic final class SnowflakeShardingKeyGenerator implements ShardingKeyGenerator{\n @Getter\n @Setter\n private Properties properties = new Properties();\n \n public String getType() {\n return \"SNOWFLAKE\";\n }\n \n public synchronized Comparable generateKey() {\n \t/**\n \t * Current system time in milliseconds \n \t */ \n long currentMilliseconds = timeService.getCurrentMillis();\n /**\n * Judge whether the waiting time is poor , if necessary , Then the waiting time goes by , And then get the current system time \n */ \n if (waitTolerateTimeDifferenceIfNeed(currentMilliseconds)) {\n currentMilliseconds = timeService.getCurrentMillis();\n }\n /**\n * If the last millisecond and The current system time is the same in milliseconds , In the same millisecond \n */\n if (lastMilliseconds == currentMilliseconds) {\n \t/**\n \t * & Bit and operator : Both numbers are binary , If all the corresponding bits are 1, The result is 1, Otherwise 0\n \t * When the sequence is 4095 when ,4095+1 After the new sequence and mask bit and operation, the result is 0\n \t * When the sequence is other values , Neither the bits nor the result of the operation will be 0\n \t * That is, the maximum value has been used in this millisecond sequence 4096, At this time, you need to take down a millisecond time value \n \t */\n if (0L == (sequence = (sequence + 1) & SEQUENCE_MASK)) {\n currentMilliseconds = waitUntilNextTime(currentMilliseconds);\n }\n } else {\n \t/**\n \t * The last millisecond has passed , Reset the sequence value to 1 \n \t */\n vibrateSequenceOffset();\n sequence = sequenceOffset;\n }\n lastMilliseconds = currentMilliseconds;\n \n /**\n * XX......XX XX000000 00000000 00000000\t Time difference XX\n * \t\tXXXXXX XXXX0000 00000000\t machine ID XX\n * \t\t XXXX XXXXXXXX\t Serial number XX\n * Three parts | Bitwise OR operation : If all the corresponding bits are 0, The result is 0, Otherwise 1\n */\n return ((currentMilliseconds - EPOCH) << TIMESTAMP_LEFT_SHIFT_BITS) | (getWorkerId() << WORKER_ID_LEFT_SHIFT_BITS) | sequence;\n }\n \n /**\n * Judge whether the waiting time is poor \n */\n @SneakyThrows\n private boolean waitTolerateTimeDifferenceIfNeed(final long currentMilliseconds) {\n \t/**\n \t * If you get ID The last time in MS is less than or equal to the current system time Ms , It's normal , You don't have to wait \n \t */\n if (lastMilliseconds <= currentMilliseconds) {\n return false;\n }\n /**\n * ===> When the clock goes back ( The time to generate the sequence is longer than that of the current system ), Need to wait time difference \n */\n /**\n * obtain ID The time difference between the last millisecond of the current system time minus the number of milliseconds of the current system time \n */\n long timeDifferenceMilliseconds = lastMilliseconds - currentMilliseconds;\n /**\n * Time difference is less than the maximum tolerance time difference , That is, it is still within the time difference of clock callback \n */\n Preconditions.checkState(timeDifferenceMilliseconds < getMaxTolerateTimeDifferenceMilliseconds(), \n \"Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds\", lastMilliseconds, currentMilliseconds);\n /**\n * Thread sleep time difference \n */\n Thread.sleep(timeDifferenceMilliseconds);\n return true;\n }\n \n // Configured machine ID\n private long getWorkerId() {\n long result = Long.valueOf(properties.getProperty(\"worker.id\", String.valueOf(WORKER_ID)));\n Preconditions.checkArgument(result >= 0L && result < WORKER_ID_MAX_VALUE);\n return result;\n }\n \n private int getMaxTolerateTimeDifferenceMilliseconds() {\n return Integer.valueOf(properties.getProperty(\"max.tolerate.time.difference.milliseconds\", String.valueOf(MAX_TOLERATE_TIME_DIFFERENCE_MILLISECONDS)));\n }\n \n private long waitUntilNextTime(final long lastTime) {\n long result = timeService.getCurrentMillis();\n while (result <= lastTime) {\n result = timeService.getCurrentMillis();\n }\n return result;\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" But from "},{"type":"codeinline","content":[{"type":"text","text":"SNOWFLAKE"}]},{"type":"text","text":" The primary key generated by the scheme ID Look at ,"},{"type":"codeinline","content":[{"type":"text","text":"order_id"}]},{"type":"text","text":" It's a 18 A long integer number of bits , Did you find it too long , to want to "},{"type":"codeinline","content":[{"type":"text","text":"MySQL"}]},{"type":"text","text":" That kind of 0 How to realize the incremental self increasing primary key ? Don't worry. , The solution will be given in the back !"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/06/06077bd1fd0672c46b8917c5b0b711b0.png","alt":"SNOWFLAKE Primary key ID","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":" Customize "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"sharding-jdbc"}]},{"type":"text","text":" utilize "},{"type":"codeinline","content":[{"type":"text","text":"SPI"}]},{"type":"text","text":" Full name ( "},{"type":"codeinline","content":[{"type":"text","text":"Service Provider Interface"}]},{"type":"text","text":") Mechanism to expand the primary key generation rules , This is a service discovery mechanism , By scanning the project path "},{"type":"codeinline","content":[{"type":"text","text":"META-INF/services"}]},{"type":"text","text":" The files under the , And automatically loads the classes defined in the file ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" In fact, it is relatively simple to implement a custom primary key generator , There are only two steps ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" First step , Realization "},{"type":"codeinline","content":[{"type":"text","text":"ShardingKeyGenerator"}]},{"type":"text","text":" Interface , And rewrite its internal methods , among "},{"type":"codeinline","content":[{"type":"text","text":"getType()"}]},{"type":"text","text":" The method is a user-defined primary key production scheme type 、"},{"type":"codeinline","content":[{"type":"text","text":"generateKey()"}]},{"type":"text","text":" The method is to generate the rules of primary key ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" The following code uses "},{"type":"codeinline","content":[{"type":"text","text":"AtomicInteger"}]},{"type":"text","text":" To simulate and implement an ordered self increasing ID Generate ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"/**\n * @Author: xiaofu\n * @Description: Custom key generator \n */\n@Component\npublic class MyShardingKeyGenerator implements ShardingKeyGenerator {\n\n\n private final AtomicInteger count = new AtomicInteger();\n\n /**\n * Custom generation scheme type \n */\n @Override\n public String getType() {\n return \"XXX\";\n }\n\n /**\n * The core approach - Generate primary key ID\n */\n @Override\n public Comparable generateKey() {\n return count.incrementAndGet();\n }\n\n @Override\n public Properties getProperties() {\n return null;\n }\n\n @Override\n public void setProperties(Properties properties) {\n\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" The second step , Because of the use of "},{"type":"codeinline","content":[{"type":"text","text":"SPI"}]},{"type":"text","text":" The mechanism realizes the function expansion , We will be having "},{"type":"codeinline","content":[{"type":"text","text":"META-INF/services"}]},{"type":"text","text":" The file is configured with a user-defined primary key generator class ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"com.xiaofu.sharding.key.MyShardingKeyGenerator"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6a/6a56178a8f7fbd4d35813d74dbc1526c.png","alt":" Custom primary key SPI To configure ","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" We'll test these things , Configure defined primary key generation type "},{"type":"codeinline","content":[{"type":"text","text":"XXX"}]},{"type":"text","text":", And insert a few pieces of data to see the effect ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id\nspring.shardingsphere.sharding.tables.t_order.key-generator.type=XXX"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Through the console SQL Parsing logs found ,"},{"type":"codeinline","content":[{"type":"text","text":"order_id"}]},{"type":"text","text":" The field has been inserted into the record in an ordered auto increment manner , It shows that the configuration is OK ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fa/fa85d1e74617da14b5e7fea736e14ab4.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":" Take one against nine "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Since you can customize the generation scheme , So there are many ways to realize distributed primary keys , I think of this one I wrote before "},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s?_biz=MzAxNTM4NzAyNg==&mid=2247483785&idx=1&sn=8b828a8ae1701b810fe3969be536cb14&chksm=9b859174acf21862f0b95e0502a1a441c496a5488f5466b2e147d7bb9de072bde37c4db25d7a&token=113284294&lang=zhCN#rd","title":""},"content":[{"type":"text","text":"《9 Kind of Distributed ID Generation scheme 》"}]},{"type":"text","text":", Discover that it can be perfectly compatible with , Here's a selection of sound of dripping water ("},{"type":"codeinline","content":[{"type":"text","text":"Tinyid"}]},{"type":"text","text":") Let's practice , Because it's a separate distributed ID Build service , So we have to build the environment first ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Tinyid"}]},{"type":"text","text":" Service provision of "},{"type":"codeinline","content":[{"type":"text","text":"Http"}]},{"type":"text","text":" and "},{"type":"codeinline","content":[{"type":"text","text":"Tinyid-client"}]},{"type":"text","text":" Two access modes , Use below "},{"type":"codeinline","content":[{"type":"text","text":"Tinyid-client "}]},{"type":"text","text":" Way to use quickly , Read more details in this article , It's been introduced too many times ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Tinyid Service establishment "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" First pull the source code "},{"type":"codeinline","content":[{"type":"text","text":"https://github.com/didi/tinyid.git"}]},{"type":"text","text":"."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Because it is distributed based on the segment pattern ID, So it depends on the database , To create the corresponding table "},{"type":"codeinline","content":[{"type":"text","text":"tiny_id_info"}]},{"type":"text","text":" 、"},{"type":"codeinline","content":[{"type":"text","text":"tiny_id_token"}]},{"type":"text","text":" And insert the default data ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"\nCREATE TABLE `tiny_id_info` (\n\t`id` BIGINT (20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT ' Since the primary key ',\n\t`biz_type` VARCHAR (63) NOT NULL DEFAULT '' COMMENT ' Business types , only ',\n\t`begin_id` BIGINT (20) NOT NULL DEFAULT '0' COMMENT ' Start id, Record only the initial value , No other meaning . On initialization begin_id and max_id It should be the same ',\n\t`max_id` BIGINT (20) NOT NULL DEFAULT '0' COMMENT ' At present, the biggest id',\n\t`step` INT (11) DEFAULT '0' COMMENT ' step ',\n\t`delta` INT (11) NOT NULL DEFAULT '1' COMMENT ' Every time id The incremental ',\n\t`remainder` INT (11) NOT NULL DEFAULT '0' COMMENT ' remainder ',\n\t`create_time` TIMESTAMP NOT NULL DEFAULT '2010-01-01 00:00:00' COMMENT ' Creation time ',\n\t`update_time` TIMESTAMP NOT NULL DEFAULT '2010-01-01 00:00:00' COMMENT ' Update time ',\n\t`version` BIGINT (20) NOT NULL DEFAULT '0' COMMENT ' Version number ',\n\tPRIMARY KEY (`id`),\n\tUNIQUE KEY `uniq_biz_type` (`biz_type`)\n) ENGINE = INNODB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8 COMMENT 'id Information sheet ';\n\nCREATE TABLE `tiny_id_token` (\n\t`id` INT (11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT ' Self increasing id',\n\t`token` VARCHAR (255) NOT NULL DEFAULT '' COMMENT 'token',\n\t`biz_type` VARCHAR (63) NOT NULL DEFAULT '' COMMENT ' this token Accessible business type ID ',\n\t`remark` VARCHAR (255) NOT NULL DEFAULT '' COMMENT ' remarks ',\n\t`create_time` TIMESTAMP NOT NULL DEFAULT '2010-01-01 00:00:00' COMMENT ' Creation time ',\n\t`update_time` TIMESTAMP NOT NULL DEFAULT '2010-01-01 00:00:00' COMMENT ' Update time ',\n\tPRIMARY KEY (`id`)\n) ENGINE = INNODB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8 COMMENT 'token Information sheet ';\n\nINSERT INTO `tiny_id_token` (`id`, `token`, `biz_type`, `remark`, `create_time`, `update_time`) VALUES ('1', '0f673adf80504e2eaa552f5d791b644c', 'order', '1', '2017-12-14 16:36:46', '2017-12-14 16:36:48');\n\nINSERT INTO `tiny_id_info` (`id`, `biz_type`, `begin_id`, `max_id`, `step`, `delta`, `remainder`, `create_time`, `update_time`, `version`) VALUES ('1', 'order', '1', '1', '100000', '1', '0', '2018-07-21 23:52:58', '2018-07-22 23:19:27', '1');\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" And in "},{"type":"codeinline","content":[{"type":"text","text":"Tinyid"}]},{"type":"text","text":" Configure the data source information of the upper table in the service "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"datasource.tinyid.primary.url=jdbc:mysql://47.93.6.e:3306/ds-0?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8\ndatasource.tinyid.primary.username=root\ndatasource.tinyid.primary.password=root"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" The final project "},{"type":"codeinline","content":[{"type":"text","text":"maven install"}]},{"type":"text","text":" , Right click "},{"type":"codeinline","content":[{"type":"text","text":"TinyIdServerApplication"}]},{"type":"text","text":" Start the service , "},{"type":"codeinline","content":[{"type":"text","text":"Tinyid"}]},{"type":"text","text":" Distributed ID The build service is finished ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":" Customize Tinyid Primary key type "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Tinyid"}]},{"type":"text","text":" After the service is built, we will introduce it into the project , Create a new "},{"type":"codeinline","content":[{"type":"text","text":"tinyid_client.properties"}]},{"type":"text","text":" Add... To the file "},{"type":"codeinline","content":[{"type":"text","text":"tinyid.server"}]},{"type":"text","text":" and "},{"type":"codeinline","content":[{"type":"text","text":"tinyid.token"}]},{"type":"text","text":" attribute ,"},{"type":"codeinline","content":[{"type":"text","text":"token"}]},{"type":"text","text":" Before SQL Pre inserted user data ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"# tinyid Distributed ID\n# Service address \ntinyid.server=127.0.0.1:9999\n# Business token\ntinyid.token=0f673adf80504e2eaa552f5d791b644c"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Get in code ID It's simpler , Just one line of code , Business types "},{"type":"codeinline","content":[{"type":"text","text":"order"}]},{"type":"text","text":" Before SQ L Pre inserted data ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Long id = TinyId.nextId(\"order\");"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" We started customizing "},{"type":"codeinline","content":[{"type":"text","text":" Tinyid"}]},{"type":"text","text":" Implementation class of primary key generation type "},{"type":"codeinline","content":[{"type":"text","text":"TinyIdShardingKeyGenerator "}]},{"type":"text","text":" ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * @Author: xiaofu\n * @Description: Custom key generator \n */\n@Component\npublic class TinyIdShardingKeyGenerator implements ShardingKeyGenerator {\n \n /**\n * Custom generation scheme type \n */\n @Override\n public String getType() {\n return \"tinyid\";\n }\n\n /**\n * The core approach - Generate primary key ID\n */\n @Override\n public Comparable generateKey() {\n \n Long id = TinyId.nextId(\"order\");\n \n return id;\n }\n\n @Override\n public Properties getProperties() {\n return null;\n }\n\n @Override\n public void setProperties(Properties properties) {\n\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" And enable... In the configuration file "},{"type":"codeinline","content":[{"type":"text","text":" Tinyid"}]},{"type":"text","text":" Primary key generation type , This is the end of the configuration , Test it quickly ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"# Primary key field \nspring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id\n# Primary key ID Generation scheme \nspring.shardingsphere.sharding.tables.t_order.key-generator.type=tinyid"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":" test Tinyid Primary key "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Insert the order record into the database and test it , Primary key ID Field "},{"type":"codeinline","content":[{"type":"text","text":"order_id"}]},{"type":"text","text":" It's increasing for the trend , "},{"type":"codeinline","content":[{"type":"text","text":" Tinyid"}]},{"type":"text","text":" The service was successfully connected to , perfect !"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/26/26a5e37467173714105788c558b4cb36.png","alt":" Insert picture description here ","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":" summary "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" The following eight generation methods are referred to "},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s?_biz=MzAxNTM4NzAyNg==&mid=2247483785&idx=1&sn=8b828a8ae1701b810fe3969be536cb14&chksm=9b859174acf21862f0b95e0502a1a441c496a5488f5466b2e147d7bb9de072bde37c4db25d7a&token=113284294&lang=zhCN#rd","title":""},"content":[{"type":"text","text":"《9 Kind of Distributed ID Generation scheme 》"}]},{"type":"text","text":" Access on demand , It is relatively simple as a whole, and it is not implemented in turn here ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Case study GitHub Address :https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-sharding-jdbc"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" If it works for you , welcome Looking at 、 give the thumbs-up 、 forward , Your approval is my biggest motivation ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Hundreds of e-book technologies have been sorted out , To my friends . Pay attention to the public name and reply "},{"type":"text","marks":[{"type":"strong"}],"text":"666"},{"type":"text","text":" Get it yourself . Set up a technology exchange group with some friends , Discuss technology together 、 Share technical information , It aims to learn and improve together , If you are interested, please join us !"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}

版权声明
本文为[InfoQ]所创,转载请带上原文链接,感谢