{"data":{"post":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/","date":"2018-04-09"},"html":"<p>TL;DR: If a race condition between two MySQL transactions appears, the row\nwith <code class=\"language-text\">ID = N</code> may appear in the database <em>BEFORE</em> another row with <code class=\"language-text\">ID &lt; N</code>.</p>\n<h2>The task</h2>\n<p>Last week, I’ve been asked to build a microservice that will be responsible for\npolling a table for data and pushing it to a Kafka topic. As the table contains\nimmutable events, it’d wise to use some kind of incremental loading.</p>\n<h2>The tool</h2>\n<p>Confluent JDBC Connector (<a href=\"https://docs.confluent.io/current/connect/connect-jdbc/docs/index.html\">see more</a>)\nis a ready-made add-on exploiting Kafka Connect possiblities, it simplifies\nbuilding such a service to few lines of properties files and the data just flows… ;)</p>\n<p>However, one needs to set the properties carefully, adjusting each of them\nto the particular use case. One of them is the <a href=\"https://docs.confluent.io/current/connect/connect-jdbc/docs/source_config_options.html#mode\">mode</a>,\nwhich defines how the table should be queried for new rows. By default,\nit adopts the <code class=\"language-text\">incrementing</code> strategy, which should be fine for most. At least,\nthe docs don’t mention any kind of risks involved here.</p>\n<p>Beware, it’s a trap! (At least with MySQL that I had to use here.)</p>\n<h2>The trap</h2>\n<p>We need three terminals here, let’s call them A, B and C.</p>\n<p>In the terminal A, we create an empty table <code class=\"language-text\">foo</code> (a very simple one -\nauto<em>increment primary key + created</em>at timestamp + some text column <code class=\"language-text\">value</code>):</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">create</span> <span class=\"token keyword\">table</span> foo <span class=\"token punctuation\">(</span>\n  id <span class=\"token keyword\">int</span> <span class=\"token operator\">not</span> <span class=\"token boolean\">null</span> <span class=\"token keyword\">auto_increment</span><span class=\"token punctuation\">,</span>\n  <span class=\"token keyword\">value</span> <span class=\"token keyword\">char</span><span class=\"token punctuation\">(</span><span class=\"token number\">30</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">not</span> <span class=\"token boolean\">null</span><span class=\"token punctuation\">,</span>\n  created_at <span class=\"token keyword\">timestamp</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">current_timestamp</span><span class=\"token punctuation\">,</span>\n  <span class=\"token keyword\">primary</span> <span class=\"token keyword\">key</span> <span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nQuery OK<span class=\"token punctuation\">,</span> <span class=\"token number\">0</span> <span class=\"token keyword\">rows</span> affected <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">08</span> sec<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">select</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">from</span> foo<span class=\"token punctuation\">;</span>\n\nEmpty <span class=\"token keyword\">set</span> <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">00</span> sec<span class=\"token punctuation\">)</span></code></pre></div>\n<p>OK, done - created and empty. Let’s use the second connection, terminal B, to start\na new transaction and insert a row <code class=\"language-text\">alfa</code> (I’ll use\n<a href=\"https://en.wikipedia.org/wiki/NATO_phonetic_alphabet\">the Alphabet</a> to maintain a readable order).</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">start</span> <span class=\"token keyword\">transaction</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">insert</span> <span class=\"token keyword\">into</span> foo <span class=\"token punctuation\">(</span><span class=\"token keyword\">value</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">values</span> <span class=\"token punctuation\">(</span><span class=\"token string\">'alfa'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>Since we’re in the middle on an uncommited transaction (with defualt isolation level),\n<code class=\"language-text\">alfa</code> in not yet visible for connection A.</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">select</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">from</span> foo<span class=\"token punctuation\">;</span>\n\nEmpty <span class=\"token keyword\">set</span> <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">00</span> sec<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Let’s use the last connection, C, to make an insert of <code class=\"language-text\">bravo</code> row (with autocommit).</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">insert</span> <span class=\"token keyword\">into</span> foo <span class=\"token punctuation\">(</span><span class=\"token keyword\">value</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">values</span> <span class=\"token punctuation\">(</span><span class=\"token string\">'bravo'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nQuery OK<span class=\"token punctuation\">,</span> <span class=\"token number\">1</span> <span class=\"token keyword\">row</span> affected <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">01</span> sec<span class=\"token punctuation\">)</span></code></pre></div>\n<p>This should be visible from now on for all other connections, that’s what terminal A says:</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">select</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">from</span> foo<span class=\"token punctuation\">;</span>\n\n<span class=\"token operator\">+</span><span class=\"token comment\">----+-------+---------------------+</span>\n<span class=\"token operator\">|</span> id <span class=\"token operator\">|</span> <span class=\"token keyword\">value</span> <span class=\"token operator\">|</span> created_at          <span class=\"token operator\">|</span>\n<span class=\"token operator\">+</span><span class=\"token comment\">----+-------+---------------------+</span>\n<span class=\"token operator\">|</span>  <span class=\"token number\">2</span> <span class=\"token operator\">|</span> bravo <span class=\"token operator\">|</span> <span class=\"token number\">2018</span><span class=\"token operator\">-</span><span class=\"token number\">04</span><span class=\"token operator\">-</span><span class=\"token number\">09</span> <span class=\"token number\">13</span>:<span class=\"token number\">13</span>:<span class=\"token number\">51</span> <span class=\"token operator\">|</span>\n<span class=\"token operator\">+</span><span class=\"token comment\">----+-------+---------------------+</span>\n<span class=\"token number\">1</span> <span class=\"token keyword\">row</span> <span class=\"token operator\">in</span> <span class=\"token keyword\">set</span> <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">00</span> sec<span class=\"token punctuation\">)</span></code></pre></div>\n<p>It’s there! As you can notice, it got assigned the <code class=\"language-text\">ID = 2</code>, because <code class=\"language-text\">ID = 1</code>\nhad been previously allocated for the <code class=\"language-text\">alfa</code> row. But hey, where is it?!</p>\n<p>Uncommited! Hanging in the air!</p>\n<p>Now we commit the connection B transation:</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">commit</span><span class=\"token punctuation\">;</span>\n\nQuery OK<span class=\"token punctuation\">,</span> <span class=\"token number\">0</span> <span class=\"token keyword\">rows</span> affected <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">02</span> sec<span class=\"token punctuation\">)</span></code></pre></div>\n<p>…and run a query using connection A:</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">select</span> <span class=\"token operator\">*</span> <span class=\"token keyword\">from</span> foo<span class=\"token punctuation\">;</span>\n\n<span class=\"token operator\">+</span><span class=\"token comment\">----+-------+---------------------+</span>\n<span class=\"token operator\">|</span> id <span class=\"token operator\">|</span> <span class=\"token keyword\">value</span> <span class=\"token operator\">|</span> created_at          <span class=\"token operator\">|</span>\n<span class=\"token operator\">+</span><span class=\"token comment\">----+-------+---------------------+</span>\n<span class=\"token operator\">|</span>  <span class=\"token number\">1</span> <span class=\"token operator\">|</span> alfa  <span class=\"token operator\">|</span> <span class=\"token number\">2018</span><span class=\"token operator\">-</span><span class=\"token number\">04</span><span class=\"token operator\">-</span><span class=\"token number\">09</span> <span class=\"token number\">13</span>:<span class=\"token number\">13</span>:<span class=\"token number\">21</span> <span class=\"token operator\">|</span>\n<span class=\"token operator\">|</span>  <span class=\"token number\">2</span> <span class=\"token operator\">|</span> bravo <span class=\"token operator\">|</span> <span class=\"token number\">2018</span><span class=\"token operator\">-</span><span class=\"token number\">04</span><span class=\"token operator\">-</span><span class=\"token number\">09</span> <span class=\"token number\">13</span>:<span class=\"token number\">13</span>:<span class=\"token number\">51</span> <span class=\"token operator\">|</span>\n<span class=\"token operator\">+</span><span class=\"token comment\">----+-------+---------------------+</span>\n<span class=\"token number\">2</span> <span class=\"token keyword\">rows</span> <span class=\"token operator\">in</span> <span class=\"token keyword\">set</span> <span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">01</span> sec<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Now, both <code class=\"language-text\">alfa</code> and <code class=\"language-text\">bravo</code> rows are visible.</p>\n<h2>The issue</h2>\n<p>During the between-commit phase, the row <code class=\"language-text\">bravo</code> with <code class=\"language-text\">ID = 2</code> was visible\nfor other connections while the row <code class=\"language-text\">alfa</code> (<code class=\"language-text\">ID = 1</code>) was still uncommited, thus\nnot visible for others.</p>\n<p>This is why I claim that in edge cases, when a race condition between transaction\noccurs, the <code class=\"language-text\">auto_increment</code> breaks its monotonic property. This is due to the fact\nthat the value is allocated on insert, not on commit.</p>\n<p>For the microservice I’m developing, this is a serious threat. Consider that\nwe query the db during this short between-commit phase:</p>\n<ol>\n<li>we retrieve a single row, <code class=\"language-text\">ID = 2</code>,</li>\n<li>we process this batch of one row,</li>\n<li>we store the <code class=\"language-text\">ID = 2</code> state for the next batch, telling it “you should\nadd <code class=\"language-text\">where ID &gt; 2</code> to your query”.</li>\n</ol>\n<p>We’ve just ommited the <code class=\"language-text\">alfa</code> row!</p>\n<h2>Solution ideas</h2>\n<p>Here’s a list of proposals that might work (or might not):</p>\n<ol>\n<li>\n<p>Exploit the <code class=\"language-text\">created_at</code> column to improve the situation? I don’t think it’ll help,\nbut that’s one of the modes that Kafka JDBC connector can operate in.</p>\n</li>\n<li>\n<p>Wait X seconds until all transactions with <code class=\"language-text\">ID &lt; N</code> are commited (e.g. <a href=\"https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout\"> innodb<em>lock</em>wait_timeout</a> + 5 seconds).</p>\n</li>\n<li>\n<p>Dump whole table instead of incremental loading.</p>\n</li>\n<li>\n<p>Mark the already pushed rows with a flag, query with <code class=\"language-text\">where flag = false</code>.</p>\n</li>\n</ol>\n<p>In case of any questions, comments, don’t hestitate to <a href=\"https://twitter.com/maciejpapiez\">reach out</a>.</p>","frontmatter":{"title":"Is MySQL's auto_increment really monotonic?","subTitle":"Why you shouldn't rely on auto_increment feature in some cases.","postAuthor":"Maciej Papież","cover":"/img/mysql.png"}},"tags":{"group":[{"name":"$OSTYPE","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":".env","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":".nvrmc","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"AUTO_INCREMENT","totalCount":1,"edges":[{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}}]},{"name":"Angular","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Command","totalCount":1,"edges":[{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"DQL","totalCount":2,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}},{"node":{"fields":{"slug":"/mysql-decimal-format/"}}}]},{"name":"Data Transfer Object","totalCount":1,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}}]},{"name":"Docker","totalCount":3,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/quick-import-of-mysql-database-dump/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Docker Compose","totalCount":3,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/quick-import-of-mysql-database-dump/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Doctrine","totalCount":2,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}},{"node":{"fields":{"slug":"/mysql-decimal-format/"}}}]},{"name":"Doctrine NEW","totalCount":1,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}}]},{"name":"ES7","totalCount":1,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}}]},{"name":"Elastica","totalCount":1,"edges":[{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Elasticsearch","totalCount":1,"edges":[{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Elasticsearch script","totalCount":1,"edges":[{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Express","totalCount":1,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}}]},{"name":"Git","totalCount":2,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}},{"node":{"fields":{"slug":"/git-reverting-branch-removal/"}}}]},{"name":"Git renamed","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}}]},{"name":"HTTP","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"JavaScript","totalCount":3,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}},{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}},{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"Kafka","totalCount":1,"edges":[{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}}]},{"name":"MySQL","totalCount":4,"edges":[{"node":{"fields":{"slug":"/mysql-decimal-format/"}}},{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}},{"node":{"fields":{"slug":"/php-with-mysql-8/"}}},{"node":{"fields":{"slug":"/quick-import-of-mysql-database-dump/"}}}]},{"name":"MySQL 8","totalCount":1,"edges":[{"node":{"fields":{"slug":"/php-with-mysql-8/"}}}]},{"name":"Node.js","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"ORM","totalCount":1,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}}]},{"name":"PDO","totalCount":1,"edges":[{"node":{"fields":{"slug":"/php-with-mysql-8/"}}}]},{"name":"PDO_MYSQL","totalCount":1,"edges":[{"node":{"fields":{"slug":"/php-with-mysql-8/"}}}]},{"name":"PHP","totalCount":6,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}},{"node":{"fields":{"slug":"/mysql-decimal-format/"}}},{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/php-with-mysql-8/"}}},{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}},{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"Phing","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"Promise","totalCount":1,"edges":[{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"Python","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"React","totalCount":2,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Redux","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"Redux store","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"SPA","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Slack","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"Spotify","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"Travis","totalCount":2,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}},{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Vue","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"XDEBUG_CONFIG","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":"XDebug","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":"ai","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"amazon","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"apple-watch","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"asp.net core","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"async","totalCount":2,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}},{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"autocomplete","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"await","totalCount":2,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}},{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"aws","totalCount":3,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}},{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}},{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"aws.cli","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"bash","totalCount":2,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"bitbucket","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"blazor","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"build","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"builder pattern","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"c#","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"ci","totalCount":1,"edges":[{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}}]},{"name":"claude-code","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"cognito","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"colors","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"continuous integration","totalCount":1,"edges":[{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}}]},{"name":"decimal","totalCount":1,"edges":[{"node":{"fields":{"slug":"/mysql-decimal-format/"}}}]},{"name":"docker","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"ec2","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"environment","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"equals","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"flysystem","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"front-end","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"git","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"git commit","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}}]},{"name":"git reflog","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-reverting-branch-removal/"}}}]},{"name":"git status","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}}]},{"name":"github","totalCount":3,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}},{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}},{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"guide","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"hashcode","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"hibernate","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"java","totalCount":2,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}},{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"java.time","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"jaxb","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"jdk8","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"jpa","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"maven","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"middleware","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"mono","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"multi-stage","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"naming","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"networking","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"ntp","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"nvm","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"persistence","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"port 4381","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"pr","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"production","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"project","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"pull","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"qa","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"razor","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"reducer","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"regex","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"repo","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"repository","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"s3","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"sass","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"setup","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"skills","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"styles","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"symfony","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"templates","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"test-automation","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"transaction","totalCount":1,"edges":[{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}}]},{"name":"travis","totalCount":1,"edges":[{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}}]},{"name":"tutorial","totalCount":2,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"ubuntu","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"unsupported","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"uuid","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"variables","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"wasm","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"watchos","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"web","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]}]},"author":{"id":"37bda159-ff45-50c9-aeba-18326b7ca66b","childMarkdownRemark":{"html":"<p><strong>XSolve</strong> We are Agile Software House focused on PHP/Symfony, #JavaScript, #Java and #Mobile (iOS, Android, Windows Phone) #Inc5000 European company in 2018.\n<br>\n<a href=\"https://xsolve.software\">xsolve.software</a></p>"}},"footnote":{"id":"b4474c9b-7be6-5f34-866a-cdfffa885bce","childMarkdownRemark":{"html":"<ul>\n<li>From <a href=\"https://www.boldare.com/\">Boldare</a></li>\n<li>with <a href=\"https://github.com/greglobinski/gatsby-starter-personal-blog/\">Gatsby starter</a></li>\n<li>delivered by <a href=\"https://www.netlify.com/\">Netlify</a></li>\n</ul>"}},"site":{"siteMetadata":{"facebook":{"appId":""}}}},"pageContext":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}