<?xml version="1.0" encoding="iso-8859-1"?><!-- generator="b2evolution/4.0.3" -->
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>/dev/random - Categories: MySQL, MySQL 101</title>
		<link>http://blogs.sakienvirotech.com/index.php/random/</link>
		<atom:link rel="self" type="application/rss+xml" href="http://blogs.sakienvirotech.com/index.php/random/?tempskin=_rss2" />
		<description>/dev/random - musings from the developer's corner</description>
		<language>en-AU</language>
		<docs>http://blogs.law.harvard.edu/tech/rss</docs>
		<admin:generatorAgent rdf:resource="http://b2evolution.net/?v=4.0.3"/>
		<ttl>60</ttl>
				<item>
			<title>See you at LCA2012</title>
			<link>http://blogs.sakienvirotech.com/index.php/random/2012/01/12/see-you-at-lca2012</link>
			<pubDate>Thu, 12 Jan 2012 06:21:00 +0000</pubDate>			<dc:creator>ajdonnison</dc:creator>
			<category domain="main">Open Source, Open World</category>
<category domain="alt">MySQL</category>			<guid isPermaLink="false">779@http://blogs.sakienvirotech.com/</guid>
						<description>&lt;p&gt;&lt;a href=&quot;http://lcaunderthestars.org.au/&quot;&gt;Linux.conf.au &lt;/a&gt;this year kicks off next week in &lt;a href=&quot;http://en.wikipedia.org/wiki/Ballarat&quot;&gt;Ballarat&lt;/a&gt;, just down the road from me.&amp;#160; I&#039;ll be there and even have a &lt;a href=&quot;http://linux.conf.au/wiki/index.php/Miniconfs/HighAvailabilityAndDistributedStorage#MySQL_for_the_Developer_in_a_Post-Oracle_World&quot;&gt;speaking gig&lt;/a&gt;, not in the main conference but in the HA and Distributed Storage mini-conf before the main event.&lt;/p&gt;
&lt;p&gt;I&#039;ll be talking about MySQL&amp;#174;, the companies that now exist to support it, and the third party products that are starting to proliferate in what appears to be a community effort to address perceived shortcomings in the Oracle offerings.&amp;#160; Many of these offerings are in the HA space, and there have been some pretty amazing developments recently.&lt;/p&gt;
&lt;p&gt;So if you want to find some history of Oracle&#039;s effect on MySQL&#039;s development (and a hint, it started well before the Sun acquisition), or you want to find out what is out there to assist you in developing HA and Distributed database systems, come along.&amp;#160; I&#039;ll be wearing my &lt;a href=&quot;http://www.skysql.com/&quot;&gt;SkySQL&lt;/a&gt; shirt so I should be easy to pick.&lt;/p&gt;&lt;div class=&quot;socialbutttons&quot;&gt;&lt;div class=&quot;fbiframediv sharebuttton&quot;&gt;&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;amp;href=http://blogs.sakienvirotech.com/index.php?p=779&amp;amp;send=false&amp;amp;width=450&amp;amp;show_faces=false&amp;amp;action=like&amp;amp;colorscheme=light&amp;amp;font=arial&amp;amp;height=85&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:450px; height:85px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div class=&quot;twbutton sharebuttton&quot;&gt;&lt;a href=&quot;http://twitter.com/share&quot; class=&quot;twitter-share-button&quot; data-url=&quot;http://blogs.sakienvirotech.com/index.php?p=779&quot; data-count=&quot;horizontal&quot;&gt;Tweet&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;gplusdiv sharebuttton&quot;&gt;&lt;g:plusone href=&quot;http://blogs.sakienvirotech.com/index.php?p=779&quot;&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.sakienvirotech.com/index.php/random/2012/01/12/see-you-at-lca2012&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://blogs.sakienvirotech.com/random&quot;&gt;Saki Envirotech Blogs&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p><a href="http://lcaunderthestars.org.au/">Linux.conf.au </a>this year kicks off next week in <a href="http://en.wikipedia.org/wiki/Ballarat">Ballarat</a>, just down the road from me.&#160; I'll be there and even have a <a href="http://linux.conf.au/wiki/index.php/Miniconfs/HighAvailabilityAndDistributedStorage#MySQL_for_the_Developer_in_a_Post-Oracle_World">speaking gig</a>, not in the main conference but in the HA and Distributed Storage mini-conf before the main event.</p>
<p>I'll be talking about MySQL&#174;, the companies that now exist to support it, and the third party products that are starting to proliferate in what appears to be a community effort to address perceived shortcomings in the Oracle offerings.&#160; Many of these offerings are in the HA space, and there have been some pretty amazing developments recently.</p>
<p>So if you want to find some history of Oracle's effect on MySQL's development (and a hint, it started well before the Sun acquisition), or you want to find out what is out there to assist you in developing HA and Distributed database systems, come along.&#160; I'll be wearing my <a href="http://www.skysql.com/">SkySQL</a> shirt so I should be easy to pick.</p><div class="socialbutttons"><div class="fbiframediv sharebuttton"><iframe src="http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;href=http://blogs.sakienvirotech.com/index.php?p=779&amp;send=false&amp;width=450&amp;show_faces=false&amp;action=like&amp;colorscheme=light&amp;font=arial&amp;height=85" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:85px;" allowTransparency="true"></iframe></div><div class="twbutton sharebuttton"><a href="http://twitter.com/share" class="twitter-share-button" data-url="http://blogs.sakienvirotech.com/index.php?p=779" data-count="horizontal">Tweet</a></div><div class="gplusdiv sharebuttton"><g:plusone href="http://blogs.sakienvirotech.com/index.php?p=779"></g:plusone></div></div><div class="item_footer"><p><small><a href="http://blogs.sakienvirotech.com/index.php/random/2012/01/12/see-you-at-lca2012">Original post</a> blogged on <a href="http://blogs.sakienvirotech.com/random">Saki Envirotech Blogs</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.sakienvirotech.com/index.php/random/2012/01/12/see-you-at-lca2012#comments</comments>
			<wfw:commentRss>http://blogs.sakienvirotech.com/index.php/random/?tempskin=_rss2&#38;disp=comments&#38;p=779</wfw:commentRss>
		</item>
				<item>
			<title>MySQL 101 - Replication</title>
			<link>http://blogs.sakienvirotech.com/index.php/random/2011/11/01/mysql-101-replication</link>
			<pubDate>Tue, 01 Nov 2011 03:37:00 +0000</pubDate>			<dc:creator>ajdonnison</dc:creator>
			<category domain="alt">Open Source, Open World</category>
<category domain="alt">MySQL</category>
<category domain="main">MySQL 101</category>			<guid isPermaLink="false">772@http://blogs.sakienvirotech.com/</guid>
						<description>&lt;p&gt;So far we&#039;ve looked at many aspects of MySQL, not in any great depth, but hopefully with enough information to get you started and whet your appetite for more.&amp;#160; Now we start to look into areas that aren&#039;t in the basic tutorials.&lt;/p&gt;
&lt;p&gt;Replication is the technology that allows data to be stored on multiple servers. Typically this is used in &quot;scale out&quot; applications.&amp;#160; &quot;Scale out&quot; is used in contrast to &quot;Scale up&quot; where to scale a solution you buy a bigger box to run it on, where &quot;scale out&quot; means you buy more boxes.&amp;#160; Each has its benefits and drawbacks, with the usual benefit of scale out being that you get more bang for your buck.&lt;/p&gt;
&lt;p&gt;The way replication works in MySQL is pretty simple.&amp;#160; One server is identified as the master, and writes every transaction to a file, the binary log.&amp;#160; Other servers (and there may be many) act as slaves and request information from the master. The slave keeps track of where it got up to and asks the master for the next transaction in the file.&amp;#160; In general the master doesn&#039;t know or care where the slave is up to, it just sends out the requested transaction to whoever has the right credentials to ask for it.&lt;/p&gt;
&lt;p&gt;On the slave there are two threads running, one that requests events from the master binlog (binary log) and writes them to the relay log (which in reality is just another binlog), and the second thread that reads the relay log and executes the queries. In order to avoid non-deterministic outcomes the SQL thread is just that, a single thread.&amp;#160; Long running events can result in the replication lagging well behind the state of the master.&lt;/p&gt;
&lt;p&gt;This is the traditional asynchronous replication.&amp;#160; Newer versions of MySQL now support semi-synchronous replication as well.&amp;#160; In this mode the master will not return control back to the querying process until at least one slave reports that it has received the transaction events and written them to its own relay log.&amp;#160; Note that this is written to the relay log but not necessarily written to the database.&lt;/p&gt;
&lt;p&gt;You may wonder under what circumstance replication would be of use.&amp;#160; If your application is mainly read-intensive (as many web applications are) then replication gives you the ability to spread reads across multiple slaves to reduce contention.&amp;#160; If your application is mainly write intensive, then replication to multiple slaves will not, of itself, give you any relief.&amp;#160; Indeed, because the replication is single-threaded and all writes on the master must be written to the slaves, you can in fact hurt performance with a replicated setup.&lt;/p&gt;
&lt;p&gt;What about more than one master?&amp;#160; This is possible but requires careful thought and planning.&amp;#160; MySQL replication keeps track of which server initiated the transaction, so &quot;circular replication&quot; where a slave acts also as a master should not cause problems, however there are some serious issues to consider.&amp;#160; Take for instance a customer table with the customer ID being auto incremented.&amp;#160; What happens if there are writes to both masters in a master&amp;lt;-&amp;gt;master replication setup?&amp;#160; Both will grab the next ID in sequence, then the other will pull that transaction and try and will end up with a duplicate index error, causing replication to fail.&amp;#160; You can get around this by setting the initial auto_increment value on each server and setting the auto_increment_increment value to the number of masters in use.&amp;#160; Remebering however that both masters now have to write all traffic that goes to the pair, there is not a great deal of benefit in such an arrangement.&amp;#160; Other technologies, such as sharding, turn out to offer better scale out opportunities for multi-master deployments.&lt;/p&gt;
&lt;p&gt;There are, however, some tools to make multi-master work more easily.&amp;#160; &lt;a href=&quot;http://mysql-mmm.org/&quot;&gt;MMM (Multi-Master Replication Manager for MySQL) &lt;/a&gt;is one.&amp;#160; &lt;a href=&quot;http://code.google.com/p/mysql-master-ha/&quot;&gt;MHA (Master High Availability for MySQL)&lt;/a&gt; is somewhat different, allowing easy management of master failover.&lt;/p&gt;
&lt;p&gt;That is probably enough theory, lets look at how to build a replication system.&lt;/p&gt;
&lt;p&gt;For the master, the only requirement is that it writes its transactions to a binary log, and that it has a server ID set.&amp;#160; To do this we need to add the following to the my.cnf file:&lt;/p&gt;
&lt;pre&gt;server-id = 1&lt;br /&gt;log_bin = /var/log/mysql/mysql-bin.log&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;The server-id is an integer that must be unique for all servers in the same replication set.&amp;#160; This is because of the tracking of transactions to avoid circular replication errors.&amp;#160; The log_bin is the path to the binary log file to use.&amp;#160; Each file will be appended with a sequence number to allow the server to rotate log files when they grow too large, or a flush request is received.&lt;/p&gt;
&lt;p&gt;One other value that is useful is to set an expiry on the binlogs so that they don&#039;t take over all of your disk.&amp;#160; You need to ensure that you have enough binlog capacity for normal replication lag and for handling backup/recovery, but beyond that you can get MySQL to automatically delete the older binlogs.&lt;/p&gt;
&lt;pre&gt;expire_log_days = 14&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Now the master will at least be writing transactions to the binary logs.&amp;#160; Now we have to set up to allow slaves to replicate.&amp;#160; First step is to create a user that the slaves will connect with.&amp;#160; This user must have REPLICATION SLAVE permissions to be able to read the binlog.&amp;#160; Note that this user is created on the master. As a privileged user, in the MySQL client:&lt;/p&gt;
&lt;pre&gt;CREATE USER &#039;replicator&#039;@&#039;192.168.%&#039; IDENTIFIED BY &#039;mypass&#039;;&lt;br /&gt;GRANT REPLICATION SLAVE ON *.* TO &#039;replicator&#039;@&#039;192.168.%&#039;;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;The first command creates our user, the second grants the required permissions.&amp;#160; Note that I&#039;ve used a wildcarded network address, you can also use a hostname wildcard.&lt;/p&gt;
&lt;p&gt;For the slave we need a few things, first we need to set a server-id that is not the same as the master (or any other slave we are creating). Then we need a copy of the data on the master at the point at which the slave is to be started, and we need to then tell the slave about the master.&lt;/p&gt;
&lt;p&gt;We can create the server-id in the same manner as we did for the master - but we don&#039;t need to specify a binlog (unless we are acting as a relay master).&lt;/p&gt;
&lt;pre&gt;server-id = 2&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;To get our first copy of the master data, the best idea is to use mysqldump.&amp;#160; Before we do, we need to stop the master from writing to the binary log and record its current position.&amp;#160; From the mysql command line:&lt;/p&gt;
&lt;pre&gt;FLUSH TABLES WITH READ LOCK;&lt;br /&gt;SHOW MASTER STATUS;&lt;br /&gt;+------------------+----------+--------------+------------------+&lt;br /&gt;| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |&lt;br /&gt;+------------------+----------+--------------+------------------+&lt;br /&gt;| mysql-bin.000092 |      106 |              |                  |&lt;br /&gt;+------------------+----------+--------------+------------------+&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;We need to keep this session open so that the lock remains in place, and from another terminal run a mysqldump.&lt;/p&gt;
&lt;pre&gt;mysqldump --all-databases &amp;gt; all_db.sql&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Once the backup is completed we can either drop the lock session or issue:&lt;/p&gt;
&lt;pre&gt;UNLOCK TABLES;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Great, we now have a backup and we have the position in the binary log at the point at which the backup occurred.&amp;#160; These two together provide us with all we need to create our slave.&lt;/p&gt;
&lt;p&gt;First step is to load the above SQL file into the slave.&amp;#160;&amp;#160; On the slave you can use the mysql command line client with the SQL file copied from the master.&lt;/p&gt;
&lt;pre&gt;mysql &amp;lt; all_db.sql&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;On the slave server we now need to issue a CHANGE MASTER command to tell it where the master is, and where to start replicating from.&amp;#160; This information will be written to the master.info file that is read at startup and updated by the replication process so that the slave will be able to resync with the master on restart.&lt;/p&gt;
&lt;pre&gt;CHANGE MASTER TO MASTER_HOST = &#039;master&#039;&lt;br /&gt;  MASTER_USER = &#039;replicator&#039;&lt;br /&gt;  MASTER_PASSWORD = &#039;mypass&#039;&lt;br /&gt;  MASTER_LOG_FILE = &#039;mysql-bin.000092&#039;&lt;br /&gt;  MASTER_LOG_POS = 106;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;The MASTER_HOST, MASTER_USER and MASTER_PASSWORD must match the master and the user created above with replication slave permission.&amp;#160; The MASTER_LOG_FILE and MASTER_LOG_POS come from the SHOW MASTER STATUS used when we did the backup of the master.&lt;/p&gt;
&lt;p&gt;Now all that is left to do is to start the slave processes:&lt;/p&gt;
&lt;pre&gt;START SLAVE;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;We can use the same backup and the same processes above to create as many slaves as we need.&lt;/p&gt;
&lt;p&gt;If you have to set up a complex replication scenario that is not covered by the above, you may find the &lt;a href=&quot;http://config.skysql.com/&quot;&gt;SkySQL Reference Architecture&lt;/a&gt; provisioning system useful.&amp;#160; This service creates master/slave high availability configurations and packages software and configurations together so that you can easily install a system from scratch that meets all your replication needs.&lt;/p&gt;
&lt;h3&gt;Disclaimer&lt;/h3&gt;
&lt;p&gt;I am employed by &lt;a href=&quot;http://www.skysql.com/&quot;&gt;SkySQL Ab&lt;/a&gt;, which provides &lt;a href=&quot;http://www.skysql.com/services/support&quot;&gt;support&lt;/a&gt;, &lt;a href=&quot;http://www.skysql.com/services/training&quot;&gt;training&lt;/a&gt; and &lt;a href=&quot;http://www.skysql.com/services/overview&quot;&gt;services&lt;/a&gt; for  MySQL, MariaDB and Drizzle and is staffed by many ex-MySQL AB         employees.  While I try to be unbiased in all of my public opinions,    and      my  opinions are all my own and not those of my employer, I    work  for     SkySQL  because I believe in what they are doing and    therefore   cannot  be   truly  unbiased.&lt;/p&gt;
&lt;p&gt;MySQL is a registered trademark of Oracle Corporation,&amp;#160; MariaDB is a trademark of MontyProgram, and Drizzle is a trademark.&lt;/p&gt;&lt;div class=&quot;socialbutttons&quot;&gt;&lt;div class=&quot;fbiframediv sharebuttton&quot;&gt;&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;amp;href=http://blogs.sakienvirotech.com/index.php?p=772&amp;amp;send=false&amp;amp;width=450&amp;amp;show_faces=false&amp;amp;action=like&amp;amp;colorscheme=light&amp;amp;font=arial&amp;amp;height=85&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:450px; height:85px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div class=&quot;twbutton sharebuttton&quot;&gt;&lt;a href=&quot;http://twitter.com/share&quot; class=&quot;twitter-share-button&quot; data-url=&quot;http://blogs.sakienvirotech.com/index.php?p=772&quot; data-count=&quot;horizontal&quot;&gt;Tweet&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;gplusdiv sharebuttton&quot;&gt;&lt;g:plusone href=&quot;http://blogs.sakienvirotech.com/index.php?p=772&quot;&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.sakienvirotech.com/index.php/random/2011/11/01/mysql-101-replication&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://blogs.sakienvirotech.com/random&quot;&gt;Saki Envirotech Blogs&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>So far we've looked at many aspects of MySQL, not in any great depth, but hopefully with enough information to get you started and whet your appetite for more.&#160; Now we start to look into areas that aren't in the basic tutorials.</p>
<p>Replication is the technology that allows data to be stored on multiple servers. Typically this is used in "scale out" applications.&#160; "Scale out" is used in contrast to "Scale up" where to scale a solution you buy a bigger box to run it on, where "scale out" means you buy more boxes.&#160; Each has its benefits and drawbacks, with the usual benefit of scale out being that you get more bang for your buck.</p>
<p>The way replication works in MySQL is pretty simple.&#160; One server is identified as the master, and writes every transaction to a file, the binary log.&#160; Other servers (and there may be many) act as slaves and request information from the master. The slave keeps track of where it got up to and asks the master for the next transaction in the file.&#160; In general the master doesn't know or care where the slave is up to, it just sends out the requested transaction to whoever has the right credentials to ask for it.</p>
<p>On the slave there are two threads running, one that requests events from the master binlog (binary log) and writes them to the relay log (which in reality is just another binlog), and the second thread that reads the relay log and executes the queries. In order to avoid non-deterministic outcomes the SQL thread is just that, a single thread.&#160; Long running events can result in the replication lagging well behind the state of the master.</p>
<p>This is the traditional asynchronous replication.&#160; Newer versions of MySQL now support semi-synchronous replication as well.&#160; In this mode the master will not return control back to the querying process until at least one slave reports that it has received the transaction events and written them to its own relay log.&#160; Note that this is written to the relay log but not necessarily written to the database.</p>
<p>You may wonder under what circumstance replication would be of use.&#160; If your application is mainly read-intensive (as many web applications are) then replication gives you the ability to spread reads across multiple slaves to reduce contention.&#160; If your application is mainly write intensive, then replication to multiple slaves will not, of itself, give you any relief.&#160; Indeed, because the replication is single-threaded and all writes on the master must be written to the slaves, you can in fact hurt performance with a replicated setup.</p>
<p>What about more than one master?&#160; This is possible but requires careful thought and planning.&#160; MySQL replication keeps track of which server initiated the transaction, so "circular replication" where a slave acts also as a master should not cause problems, however there are some serious issues to consider.&#160; Take for instance a customer table with the customer ID being auto incremented.&#160; What happens if there are writes to both masters in a master&lt;-&gt;master replication setup?&#160; Both will grab the next ID in sequence, then the other will pull that transaction and try and will end up with a duplicate index error, causing replication to fail.&#160; You can get around this by setting the initial auto_increment value on each server and setting the auto_increment_increment value to the number of masters in use.&#160; Remebering however that both masters now have to write all traffic that goes to the pair, there is not a great deal of benefit in such an arrangement.&#160; Other technologies, such as sharding, turn out to offer better scale out opportunities for multi-master deployments.</p>
<p>There are, however, some tools to make multi-master work more easily.&#160; <a href="http://mysql-mmm.org/">MMM (Multi-Master Replication Manager for MySQL) </a>is one.&#160; <a href="http://code.google.com/p/mysql-master-ha/">MHA (Master High Availability for MySQL)</a> is somewhat different, allowing easy management of master failover.</p>
<p>That is probably enough theory, lets look at how to build a replication system.</p>
<p>For the master, the only requirement is that it writes its transactions to a binary log, and that it has a server ID set.&#160; To do this we need to add the following to the my.cnf file:</p>
<pre>server-id = 1<br />log_bin = /var/log/mysql/mysql-bin.log<br /></pre>
<p>The server-id is an integer that must be unique for all servers in the same replication set.&#160; This is because of the tracking of transactions to avoid circular replication errors.&#160; The log_bin is the path to the binary log file to use.&#160; Each file will be appended with a sequence number to allow the server to rotate log files when they grow too large, or a flush request is received.</p>
<p>One other value that is useful is to set an expiry on the binlogs so that they don't take over all of your disk.&#160; You need to ensure that you have enough binlog capacity for normal replication lag and for handling backup/recovery, but beyond that you can get MySQL to automatically delete the older binlogs.</p>
<pre>expire_log_days = 14<br /></pre>
<p>Now the master will at least be writing transactions to the binary logs.&#160; Now we have to set up to allow slaves to replicate.&#160; First step is to create a user that the slaves will connect with.&#160; This user must have REPLICATION SLAVE permissions to be able to read the binlog.&#160; Note that this user is created on the master. As a privileged user, in the MySQL client:</p>
<pre>CREATE USER 'replicator'@'192.168.%' IDENTIFIED BY 'mypass';<br />GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'192.168.%';<br /></pre>
<p>The first command creates our user, the second grants the required permissions.&#160; Note that I've used a wildcarded network address, you can also use a hostname wildcard.</p>
<p>For the slave we need a few things, first we need to set a server-id that is not the same as the master (or any other slave we are creating). Then we need a copy of the data on the master at the point at which the slave is to be started, and we need to then tell the slave about the master.</p>
<p>We can create the server-id in the same manner as we did for the master - but we don't need to specify a binlog (unless we are acting as a relay master).</p>
<pre>server-id = 2<br /></pre>
<p>To get our first copy of the master data, the best idea is to use mysqldump.&#160; Before we do, we need to stop the master from writing to the binary log and record its current position.&#160; From the mysql command line:</p>
<pre>FLUSH TABLES WITH READ LOCK;<br />SHOW MASTER STATUS;<br />+------------------+----------+--------------+------------------+<br />| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |<br />+------------------+----------+--------------+------------------+<br />| mysql-bin.000092 |      106 |              |                  |<br />+------------------+----------+--------------+------------------+<br />1 row in set (0.00 sec)<br /></pre>
<p>We need to keep this session open so that the lock remains in place, and from another terminal run a mysqldump.</p>
<pre>mysqldump --all-databases &gt; all_db.sql<br /></pre>
<p>Once the backup is completed we can either drop the lock session or issue:</p>
<pre>UNLOCK TABLES;<br /></pre>
<p>Great, we now have a backup and we have the position in the binary log at the point at which the backup occurred.&#160; These two together provide us with all we need to create our slave.</p>
<p>First step is to load the above SQL file into the slave.&#160;&#160; On the slave you can use the mysql command line client with the SQL file copied from the master.</p>
<pre>mysql &lt; all_db.sql<br /></pre>
<p>On the slave server we now need to issue a CHANGE MASTER command to tell it where the master is, and where to start replicating from.&#160; This information will be written to the master.info file that is read at startup and updated by the replication process so that the slave will be able to resync with the master on restart.</p>
<pre>CHANGE MASTER TO MASTER_HOST = 'master'<br />  MASTER_USER = 'replicator'<br />  MASTER_PASSWORD = 'mypass'<br />  MASTER_LOG_FILE = 'mysql-bin.000092'<br />  MASTER_LOG_POS = 106;<br /></pre>
<p>The MASTER_HOST, MASTER_USER and MASTER_PASSWORD must match the master and the user created above with replication slave permission.&#160; The MASTER_LOG_FILE and MASTER_LOG_POS come from the SHOW MASTER STATUS used when we did the backup of the master.</p>
<p>Now all that is left to do is to start the slave processes:</p>
<pre>START SLAVE;<br /></pre>
<p>We can use the same backup and the same processes above to create as many slaves as we need.</p>
<p>If you have to set up a complex replication scenario that is not covered by the above, you may find the <a href="http://config.skysql.com/">SkySQL Reference Architecture</a> provisioning system useful.&#160; This service creates master/slave high availability configurations and packages software and configurations together so that you can easily install a system from scratch that meets all your replication needs.</p>
<h3>Disclaimer</h3>
<p>I am employed by <a href="http://www.skysql.com/">SkySQL Ab</a>, which provides <a href="http://www.skysql.com/services/support">support</a>, <a href="http://www.skysql.com/services/training">training</a> and <a href="http://www.skysql.com/services/overview">services</a> for  MySQL, MariaDB and Drizzle and is staffed by many ex-MySQL AB         employees.  While I try to be unbiased in all of my public opinions,    and      my  opinions are all my own and not those of my employer, I    work  for     SkySQL  because I believe in what they are doing and    therefore   cannot  be   truly  unbiased.</p>
<p>MySQL is a registered trademark of Oracle Corporation,&#160; MariaDB is a trademark of MontyProgram, and Drizzle is a trademark.</p><div class="socialbutttons"><div class="fbiframediv sharebuttton"><iframe src="http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;href=http://blogs.sakienvirotech.com/index.php?p=772&amp;send=false&amp;width=450&amp;show_faces=false&amp;action=like&amp;colorscheme=light&amp;font=arial&amp;height=85" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:85px;" allowTransparency="true"></iframe></div><div class="twbutton sharebuttton"><a href="http://twitter.com/share" class="twitter-share-button" data-url="http://blogs.sakienvirotech.com/index.php?p=772" data-count="horizontal">Tweet</a></div><div class="gplusdiv sharebuttton"><g:plusone href="http://blogs.sakienvirotech.com/index.php?p=772"></g:plusone></div></div><div class="item_footer"><p><small><a href="http://blogs.sakienvirotech.com/index.php/random/2011/11/01/mysql-101-replication">Original post</a> blogged on <a href="http://blogs.sakienvirotech.com/random">Saki Envirotech Blogs</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.sakienvirotech.com/index.php/random/2011/11/01/mysql-101-replication#comments</comments>
			<wfw:commentRss>http://blogs.sakienvirotech.com/index.php/random/?tempskin=_rss2&#38;disp=comments&#38;p=772</wfw:commentRss>
		</item>
				<item>
			<title>From MySQL to SkySQL - Reflections</title>
			<link>http://blogs.sakienvirotech.com/index.php/random/2011/10/20/from-mysql-to-skysql-reflections</link>
			<pubDate>Thu, 20 Oct 2011 02:06:00 +0000</pubDate>			<dc:creator>ajdonnison</dc:creator>
			<category domain="alt">The chattering classes</category>
<category domain="main">Open Source, Open World</category>
<category domain="alt">MySQL</category>			<guid isPermaLink="false">771@http://blogs.sakienvirotech.com/</guid>
						<description>&lt;p&gt;This month marked &lt;a href=&quot;http://www.skysql.com/&quot;&gt;SkySQL&lt;/a&gt;&#039;s first anniversary.&amp;#160; It also marks my 6 months with the company, after being with MySQL AB (and then Sun and finally Oracle) for over 5 years. As good a time as any for a look back and some musings of the future.&lt;/p&gt;
&lt;p&gt;In late 2005 I took a position in the web team (a part of Marketing) at MySQL AB.&amp;#160; It was a great company to work for, with a great team of people and a truly great spirit.&amp;#160; The idea that they were making a difference every day was palpable. I then saw it taken over by Sun Microsystems and shortly after by Oracle Corporation.&amp;#160; We went from 500 employees to 30,000 and then to 100,000.&amp;#160; My job satisfaction started to decline.&amp;#160; I felt more like I was battling for every concession rather than revelling in what we were able to achieve.&amp;#160; I needed a change.&lt;/p&gt;
&lt;p&gt;When I joined SkySQL it was like going home - I knew pretty much everyone at the company and that great spirit of family, that sense of being able to achieve great things, the coming together of like minds with a shared vision was what drew me there and continues to inspire me.&amp;#160; It is, after all, about the people.&amp;#160; The team that created the world class support that MySQL AB was renowned for, the team that developed the training courses that brought MySQL knowledge to thousands, the management that inspired me in the early days at MySQL AB were all here, doing what they do best.&lt;/p&gt;
&lt;p&gt;One of the prime reasons I moved from Oracle was that I saw from the inside the change in focus on MySQL. I saw that the team that manages the mysql.com domains cut from 6 down to 2. I saw the desperate backroom struggles to ensure the MySQL community sites were not taken down. I saw some truly stupid management decisions based solely on personal animosity rather than sound business sense. I saw the sales team starved of leads because of that stupidity. I saw the inter-departmental rivalry that instead of being a force for excellence was a block to cooperation and a stifling of innovation. I saw great talent leaving the company in an air of pessimism.&lt;/p&gt;
&lt;p&gt;What I see in SkySQL is an optimism and a sense of shared goal, a vitality and a willingness to go beyond the normal to achieve excellence. I see what we used to call the &quot;can-do&quot; spirit.&amp;#160; That ethos is what keeps me showing up at work each day, trying to do my part in the bigger picture and making SkySQL the first place you think of when you think open databases.&lt;/p&gt;
&lt;p&gt;There are some exciting things happening at SkySQL and the future is looking very bright.&amp;#160; I feel honoured to be a part of it all.&lt;/p&gt;&lt;div class=&quot;socialbutttons&quot;&gt;&lt;div class=&quot;fbiframediv sharebuttton&quot;&gt;&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;amp;href=http://blogs.sakienvirotech.com/index.php?p=771&amp;amp;send=false&amp;amp;width=450&amp;amp;show_faces=false&amp;amp;action=like&amp;amp;colorscheme=light&amp;amp;font=arial&amp;amp;height=85&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:450px; height:85px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div class=&quot;twbutton sharebuttton&quot;&gt;&lt;a href=&quot;http://twitter.com/share&quot; class=&quot;twitter-share-button&quot; data-url=&quot;http://blogs.sakienvirotech.com/index.php?p=771&quot; data-count=&quot;horizontal&quot;&gt;Tweet&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;gplusdiv sharebuttton&quot;&gt;&lt;g:plusone href=&quot;http://blogs.sakienvirotech.com/index.php?p=771&quot;&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.sakienvirotech.com/index.php/random/2011/10/20/from-mysql-to-skysql-reflections&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://blogs.sakienvirotech.com/random&quot;&gt;Saki Envirotech Blogs&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>This month marked <a href="http://www.skysql.com/">SkySQL</a>'s first anniversary.&#160; It also marks my 6 months with the company, after being with MySQL AB (and then Sun and finally Oracle) for over 5 years. As good a time as any for a look back and some musings of the future.</p>
<p>In late 2005 I took a position in the web team (a part of Marketing) at MySQL AB.&#160; It was a great company to work for, with a great team of people and a truly great spirit.&#160; The idea that they were making a difference every day was palpable. I then saw it taken over by Sun Microsystems and shortly after by Oracle Corporation.&#160; We went from 500 employees to 30,000 and then to 100,000.&#160; My job satisfaction started to decline.&#160; I felt more like I was battling for every concession rather than revelling in what we were able to achieve.&#160; I needed a change.</p>
<p>When I joined SkySQL it was like going home - I knew pretty much everyone at the company and that great spirit of family, that sense of being able to achieve great things, the coming together of like minds with a shared vision was what drew me there and continues to inspire me.&#160; It is, after all, about the people.&#160; The team that created the world class support that MySQL AB was renowned for, the team that developed the training courses that brought MySQL knowledge to thousands, the management that inspired me in the early days at MySQL AB were all here, doing what they do best.</p>
<p>One of the prime reasons I moved from Oracle was that I saw from the inside the change in focus on MySQL. I saw that the team that manages the mysql.com domains cut from 6 down to 2. I saw the desperate backroom struggles to ensure the MySQL community sites were not taken down. I saw some truly stupid management decisions based solely on personal animosity rather than sound business sense. I saw the sales team starved of leads because of that stupidity. I saw the inter-departmental rivalry that instead of being a force for excellence was a block to cooperation and a stifling of innovation. I saw great talent leaving the company in an air of pessimism.</p>
<p>What I see in SkySQL is an optimism and a sense of shared goal, a vitality and a willingness to go beyond the normal to achieve excellence. I see what we used to call the "can-do" spirit.&#160; That ethos is what keeps me showing up at work each day, trying to do my part in the bigger picture and making SkySQL the first place you think of when you think open databases.</p>
<p>There are some exciting things happening at SkySQL and the future is looking very bright.&#160; I feel honoured to be a part of it all.</p><div class="socialbutttons"><div class="fbiframediv sharebuttton"><iframe src="http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;href=http://blogs.sakienvirotech.com/index.php?p=771&amp;send=false&amp;width=450&amp;show_faces=false&amp;action=like&amp;colorscheme=light&amp;font=arial&amp;height=85" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:85px;" allowTransparency="true"></iframe></div><div class="twbutton sharebuttton"><a href="http://twitter.com/share" class="twitter-share-button" data-url="http://blogs.sakienvirotech.com/index.php?p=771" data-count="horizontal">Tweet</a></div><div class="gplusdiv sharebuttton"><g:plusone href="http://blogs.sakienvirotech.com/index.php?p=771"></g:plusone></div></div><div class="item_footer"><p><small><a href="http://blogs.sakienvirotech.com/index.php/random/2011/10/20/from-mysql-to-skysql-reflections">Original post</a> blogged on <a href="http://blogs.sakienvirotech.com/random">Saki Envirotech Blogs</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.sakienvirotech.com/index.php/random/2011/10/20/from-mysql-to-skysql-reflections#comments</comments>
			<wfw:commentRss>http://blogs.sakienvirotech.com/index.php/random/?tempskin=_rss2&#38;disp=comments&#38;p=771</wfw:commentRss>
		</item>
				<item>
			<title>MySQL 101 - More Transactions</title>
			<link>http://blogs.sakienvirotech.com/index.php/random/2011/10/17/mysql-101-more-transactions</link>
			<pubDate>Mon, 17 Oct 2011 00:33:00 +0000</pubDate>			<dc:creator>ajdonnison</dc:creator>
			<category domain="alt">Open Source, Open World</category>
<category domain="alt">MySQL</category>
<category domain="main">MySQL 101</category>			<guid isPermaLink="false">770@http://blogs.sakienvirotech.com/</guid>
						<description>&lt;p&gt;In &lt;a href=&quot;/index.php/random/2011/09/26/mysql-101-transactions&quot;&gt;our last episode &lt;/a&gt;we looked at transactions and how to create them.&amp;#160; In this episode I&#039;ll look at some of the implications of transactions, especially in a web application.&lt;/p&gt;
&lt;h2&gt;Transactions and Replication&lt;/h2&gt;
&lt;p&gt;We will discuss replication in depth later in the series, however it is sufficient for the moment to say that replication allows you to copy data in near real-time between MySQL servers and keep them synchronised.&amp;#160; What gets transferred are the changes that are made to your tables and data. So what about rolled-back (aborted) transactions?&amp;#160; Since the state after the rollback is essentially the same as the state before the transaction started, there seems little point in replicating those statements.&amp;#160; Indeed they are not replicated. Only completed transactions are.&lt;/p&gt;
&lt;p&gt;I briefly mentioned that there is an autocommit setting that means that without using a transaction block, every query becomes its own transaction.&amp;#160; In the light of replication this makes a lot of sense.&lt;/p&gt;
&lt;h2&gt;Transaction Duration&lt;/h2&gt;
&lt;p&gt;Transactions may need to lock resources so that concurrent changes don&#039;t clobber each other, while allowing other queries access to the data that may be subject to a transaction, in a consistent manner. How this is done depends on the transaction isolation level, but in all levels you can be sure that inserting into a primary key will lock that index value out from other transactions doing the same thing.&amp;#160; In general this means that the second transaction will block until the first transaction is either committed or rolled back.&amp;#160; For web, having a locked resource hanging around for any length of time is a real killer.&amp;#160; This can be avoided by keeping transactions as short as possible, and to be careful of using range-based operations.&lt;/p&gt;
&lt;p&gt;Let us say that we have two people trying to buy the same book.&amp;#160; As you saw from the previous episode the transaction we&#039;ve defined does a number of operations, all of which need to complete before the book can be bought.&amp;#160; They are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a purchase order record&lt;/li&gt;
&lt;li&gt;Create purchase order item records for the book(s) purchased&lt;/li&gt;
&lt;li&gt;Update the summary field on the purchase order record&lt;/li&gt;
&lt;li&gt;Decrement the stock count for the book(s) purchased&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you look at those steps, you could see how a web application designer might get themselves into trouble.&amp;#160; If you created a purchase order and allow multiple books to be bought, then you may be tempted to keep the transaction open while the user browses and gets all their books purchased.&amp;#160; This would be a complete disaster.&amp;#160; It would mean there was an open-ended time the transaction was held, with locks on things like the book record (for decrementing the count) and therefore the entire system would almost certainly become deadlocked at some point.&amp;#160; This is where you need to be very aware of what the logic of the application is and how to bound the transactions.&lt;/p&gt;
&lt;p&gt;In the above case we could handle this in a number of ways.&amp;#160; The easiest would be to create the purchase order record as a separate transaction, then for each book purchased, do the remaining three steps in another transaction.&amp;#160; Another way would be to separate the actual purchase order creation from the selection process.&amp;#160; You&#039;ll have seen this in process in a number of sites - where you have a Shopping Cart that you add books to and it isn&#039;t until checkout that it all ends up as a single purchase order.&lt;/p&gt;
&lt;p&gt;No matter which way you do it - remember that you should never create a transaction that is unbounded in time. And on the web that means never creating a transaction that needs user interaction within the transaction.&lt;/p&gt;
&lt;h2&gt;Short Circuited Transactions&lt;/h2&gt;
&lt;p&gt;There are some operations that, if placed within a transaction, will perform an implicit commit on the statements that have preceeded it, effectively short-circuiting the transaction and creating a multiple transaction set.&amp;#160; Things like DDL (Data Definition Language) statements that modify the table structure or add indexes will be run in their own transaction, causing an implicit commit of any statements preceeding them.&amp;#160; DDL statements, in general, cannot be rolled back as they run in their own transaction.&lt;/p&gt;
&lt;p&gt;More information on the caveats with transactions can be found in the &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.5/en/sql-syntax-transactions.html&quot;&gt;online manual reference&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Disclaimer&lt;/h3&gt;
&lt;p&gt;I am employed by &lt;a href=&quot;http://www.skysql.com/&quot;&gt;SkySQL Ab&lt;/a&gt;, which provides &lt;a href=&quot;http://www.skysql.com/services/support&quot;&gt;support&lt;/a&gt;, &lt;a href=&quot;http://www.skysql.com/services/training&quot;&gt;training&lt;/a&gt; and &lt;a href=&quot;http://www.skysql.com/services/overview&quot;&gt;services&lt;/a&gt; for  MySQL, MariaDB and Drizzle and is staffed by many ex-MySQL AB        employees.  While I try to be unbiased in all of my public opinions,   and      my  opinions are all my own and not those of my employer, I   work  for     SkySQL  because I believe in what they are doing and   therefore   cannot  be   truly  unbiased.&lt;/p&gt;
&lt;p&gt;MySQL is a registered trademark of Oracle Corporation,&amp;#160; MariaDB is a trademark of MontyProgram, and Drizzle is a trademark.&lt;/p&gt;&lt;div class=&quot;socialbutttons&quot;&gt;&lt;div class=&quot;fbiframediv sharebuttton&quot;&gt;&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;amp;href=http://blogs.sakienvirotech.com/index.php?p=770&amp;amp;send=false&amp;amp;width=450&amp;amp;show_faces=false&amp;amp;action=like&amp;amp;colorscheme=light&amp;amp;font=arial&amp;amp;height=85&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:450px; height:85px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div class=&quot;twbutton sharebuttton&quot;&gt;&lt;a href=&quot;http://twitter.com/share&quot; class=&quot;twitter-share-button&quot; data-url=&quot;http://blogs.sakienvirotech.com/index.php?p=770&quot; data-count=&quot;horizontal&quot;&gt;Tweet&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;gplusdiv sharebuttton&quot;&gt;&lt;g:plusone href=&quot;http://blogs.sakienvirotech.com/index.php?p=770&quot;&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.sakienvirotech.com/index.php/random/2011/10/17/mysql-101-more-transactions&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://blogs.sakienvirotech.com/random&quot;&gt;Saki Envirotech Blogs&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>In <a href="http://blogs.sakienvirotech.com/index.php/random/2011/09/26/mysql-101-transactions">our last episode </a>we looked at transactions and how to create them.&#160; In this episode I'll look at some of the implications of transactions, especially in a web application.</p>
<h2>Transactions and Replication</h2>
<p>We will discuss replication in depth later in the series, however it is sufficient for the moment to say that replication allows you to copy data in near real-time between MySQL servers and keep them synchronised.&#160; What gets transferred are the changes that are made to your tables and data. So what about rolled-back (aborted) transactions?&#160; Since the state after the rollback is essentially the same as the state before the transaction started, there seems little point in replicating those statements.&#160; Indeed they are not replicated. Only completed transactions are.</p>
<p>I briefly mentioned that there is an autocommit setting that means that without using a transaction block, every query becomes its own transaction.&#160; In the light of replication this makes a lot of sense.</p>
<h2>Transaction Duration</h2>
<p>Transactions may need to lock resources so that concurrent changes don't clobber each other, while allowing other queries access to the data that may be subject to a transaction, in a consistent manner. How this is done depends on the transaction isolation level, but in all levels you can be sure that inserting into a primary key will lock that index value out from other transactions doing the same thing.&#160; In general this means that the second transaction will block until the first transaction is either committed or rolled back.&#160; For web, having a locked resource hanging around for any length of time is a real killer.&#160; This can be avoided by keeping transactions as short as possible, and to be careful of using range-based operations.</p>
<p>Let us say that we have two people trying to buy the same book.&#160; As you saw from the previous episode the transaction we've defined does a number of operations, all of which need to complete before the book can be bought.&#160; They are:</p>
<ul>
<li>Create a purchase order record</li>
<li>Create purchase order item records for the book(s) purchased</li>
<li>Update the summary field on the purchase order record</li>
<li>Decrement the stock count for the book(s) purchased</li>
</ul>
<p>If you look at those steps, you could see how a web application designer might get themselves into trouble.&#160; If you created a purchase order and allow multiple books to be bought, then you may be tempted to keep the transaction open while the user browses and gets all their books purchased.&#160; This would be a complete disaster.&#160; It would mean there was an open-ended time the transaction was held, with locks on things like the book record (for decrementing the count) and therefore the entire system would almost certainly become deadlocked at some point.&#160; This is where you need to be very aware of what the logic of the application is and how to bound the transactions.</p>
<p>In the above case we could handle this in a number of ways.&#160; The easiest would be to create the purchase order record as a separate transaction, then for each book purchased, do the remaining three steps in another transaction.&#160; Another way would be to separate the actual purchase order creation from the selection process.&#160; You'll have seen this in process in a number of sites - where you have a Shopping Cart that you add books to and it isn't until checkout that it all ends up as a single purchase order.</p>
<p>No matter which way you do it - remember that you should never create a transaction that is unbounded in time. And on the web that means never creating a transaction that needs user interaction within the transaction.</p>
<h2>Short Circuited Transactions</h2>
<p>There are some operations that, if placed within a transaction, will perform an implicit commit on the statements that have preceeded it, effectively short-circuiting the transaction and creating a multiple transaction set.&#160; Things like DDL (Data Definition Language) statements that modify the table structure or add indexes will be run in their own transaction, causing an implicit commit of any statements preceeding them.&#160; DDL statements, in general, cannot be rolled back as they run in their own transaction.</p>
<p>More information on the caveats with transactions can be found in the <a href="http://dev.mysql.com/doc/refman/5.5/en/sql-syntax-transactions.html">online manual reference</a>.</p>
<h3>Disclaimer</h3>
<p>I am employed by <a href="http://www.skysql.com/">SkySQL Ab</a>, which provides <a href="http://www.skysql.com/services/support">support</a>, <a href="http://www.skysql.com/services/training">training</a> and <a href="http://www.skysql.com/services/overview">services</a> for  MySQL, MariaDB and Drizzle and is staffed by many ex-MySQL AB        employees.  While I try to be unbiased in all of my public opinions,   and      my  opinions are all my own and not those of my employer, I   work  for     SkySQL  because I believe in what they are doing and   therefore   cannot  be   truly  unbiased.</p>
<p>MySQL is a registered trademark of Oracle Corporation,&#160; MariaDB is a trademark of MontyProgram, and Drizzle is a trademark.</p><div class="socialbutttons"><div class="fbiframediv sharebuttton"><iframe src="http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;href=http://blogs.sakienvirotech.com/index.php?p=770&amp;send=false&amp;width=450&amp;show_faces=false&amp;action=like&amp;colorscheme=light&amp;font=arial&amp;height=85" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:85px;" allowTransparency="true"></iframe></div><div class="twbutton sharebuttton"><a href="http://twitter.com/share" class="twitter-share-button" data-url="http://blogs.sakienvirotech.com/index.php?p=770" data-count="horizontal">Tweet</a></div><div class="gplusdiv sharebuttton"><g:plusone href="http://blogs.sakienvirotech.com/index.php?p=770"></g:plusone></div></div><div class="item_footer"><p><small><a href="http://blogs.sakienvirotech.com/index.php/random/2011/10/17/mysql-101-more-transactions">Original post</a> blogged on <a href="http://blogs.sakienvirotech.com/random">Saki Envirotech Blogs</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.sakienvirotech.com/index.php/random/2011/10/17/mysql-101-more-transactions#comments</comments>
			<wfw:commentRss>http://blogs.sakienvirotech.com/index.php/random/?tempskin=_rss2&#38;disp=comments&#38;p=770</wfw:commentRss>
		</item>
				<item>
			<title>MySQL 101 - Transactions</title>
			<link>http://blogs.sakienvirotech.com/index.php/random/2011/09/26/mysql-101-transactions</link>
			<pubDate>Mon, 26 Sep 2011 07:16:00 +0000</pubDate>			<dc:creator>ajdonnison</dc:creator>
			<category domain="alt">Open Source, Open World</category>
<category domain="alt">MySQL</category>
<category domain="main">MySQL 101</category>			<guid isPermaLink="false">766@http://blogs.sakienvirotech.com/</guid>
						<description>&lt;p&gt;We&#039;ve now come a long way since &lt;a href=&quot;/index.php/random/2011/09/05/mysql-101-creating-your-first&quot;&gt;our first steps&lt;/a&gt; at creating our online bookshop database. Now we need to start to think about how to sell the books and store details about the sales.&amp;#160; This is the time we need to start understanding database transactions.&lt;/p&gt;
&lt;p&gt;Database transactions are very similar to real world transactions. They define a set of steps required to happen together in order for a transaction to be complete.&amp;#160; A real-world example might be that you buy a trinket from a store.&amp;#160; You find the trinket, then take it to the counter, find out the price, hand over the cash and receive your trinket.&amp;#160; That is a completed transaction.&amp;#160; Should you not have the available cash, the transaction would not be able to be completed and you would need to return the item, effectively rolling back that transaction.&amp;#160; It is not a great deal different in the database, except that the transaction can be controlled to a greater degree.&lt;/p&gt;
&lt;p&gt;Before going too far, we need to build a few more tables for our database to enable us to sell our books.&amp;#160; To make life easier I&#039;ve created these tables in &lt;a href=&quot;/media/blogs/random/mysql101_bookshop_20110926.zip?mtime=1317027350&quot;&gt;this downloadable file&lt;/a&gt;.&amp;#160; You can use your favourite MySQL client to create the database for the purposes of following this episode.&amp;#160; The tables I&#039;ve created are customer, purchase_order and order_item.&amp;#160; We&#039;ll see how they work in handling a typical transaction - we can use SHOW CREATE TABLE to see how they are defined:&lt;/p&gt;
&lt;pre&gt;SHOW CREATE TABLE `customer`\G&lt;br /&gt;*************************** 1. row ***************************&lt;br /&gt;       Table: customer&lt;br /&gt;Create Table: CREATE TABLE `customer` (&lt;br /&gt;  `id` int(11) NOT NULL AUTO_INCREMENT,&lt;br /&gt;  `name` varchar(255) CHARACTER SET latin1 NOT NULL,&lt;br /&gt;  `address1` varchar(80) CHARACTER SET latin1 NOT NULL,&lt;br /&gt;  `address2` varchar(80) CHARACTER SET latin1 DEFAULT NULL,&lt;br /&gt;  `postcode` varchar(8) CHARACTER SET latin1 DEFAULT NULL,&lt;br /&gt;  `city` varchar(80) CHARACTER SET latin1 DEFAULT NULL,&lt;br /&gt;  `country` varchar(80) CHARACTER SET latin1 DEFAULT NULL,&lt;br /&gt;  `state` varchar(20) CHARACTER SET latin1 DEFAULT NULL,&lt;br /&gt;  PRIMARY KEY (`id`)&lt;br /&gt;) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;SHOW CREATE TABLE `purchase_order`\G&lt;br /&gt;*************************** 1. row ***************************&lt;br /&gt;       Table: purchase_order&lt;br /&gt;Create Table: CREATE TABLE `purchase_order` (&lt;br /&gt;  `id` int(11) NOT NULL AUTO_INCREMENT,&lt;br /&gt;  `customer` int(11) NOT NULL DEFAULT &#039;0&#039;,&lt;br /&gt;  `order_date` datetime NOT NULL,&lt;br /&gt;  `ship_date` datetime DEFAULT NULL,&lt;br /&gt;  `order_total` decimal(9,2) DEFAULT NULL,&lt;br /&gt;  PRIMARY KEY (`id`),&lt;br /&gt;  KEY `fk_order_customer` (`customer`),&lt;br /&gt;  CONSTRAINT `fk_order_customer` FOREIGN KEY (`customer`) REFERENCES `customer` (`id`) ON UPDATE CASCADE&lt;br /&gt;) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;SHOW CREATE TABLE `order_item`\G&lt;br /&gt;*************************** 1. row ***************************&lt;br /&gt;       Table: order_item&lt;br /&gt;Create Table: CREATE TABLE `order_item` (&lt;br /&gt;  `id` int(11) NOT NULL AUTO_INCREMENT,&lt;br /&gt;  `purchase_order` int(11) NOT NULL,&lt;br /&gt;  `book` int(11) NOT NULL,&lt;br /&gt;  `quantity` int(11) NOT NULL DEFAULT &#039;0&#039;,&lt;br /&gt;  `price` decimal(5,2) DEFAULT NULL,&lt;br /&gt;  PRIMARY KEY (`id`),&lt;br /&gt;  KEY `fk_item_order` (`purchase_order`),&lt;br /&gt;  KEY `fk_item_book` (`book`),&lt;br /&gt;  CONSTRAINT `fk_item_order` FOREIGN KEY (`purchase_order`) REFERENCES `purchase_order` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,&lt;br /&gt;  CONSTRAINT `fk_item_book` FOREIGN KEY (`book`) REFERENCES `book` (`id`) ON UPDATE CASCADE&lt;br /&gt;) ENGINE=InnoDB DEFAULT CHARSET=utf8&lt;br /&gt;1 row in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;You&#039;ll notice a few things that may not immediately make sense.&amp;#160; In most cases you don&#039;t want duplicate data in different tables.&amp;#160; This is why we break out things like publisher from book, for instance.&amp;#160; However in purchase_order we have an order_total value that could be derived from the order_item records, and similarly we have a price field in order_item that is the same as the price field in book.&amp;#160; There is a lot of sense in doing this however.&amp;#160; Because we are dealing with financial transactions we must ensure they can stand alone.&amp;#160; So we need to ensure that the price of the book is not whatever the current price is, but the price it was at the&amp;#160; time it was sold.&amp;#160; This is why we have the price field in two places as they are not exactly the same.&amp;#160; The order_total field is a summary data field.&amp;#160; It means that we don&#039;t necessarily have to have a complicated multi-table join if we want to find how much a customer has bought.&amp;#160; Summary data fields are often used to speed up common queries by simplifying them.&lt;/p&gt;
&lt;p&gt;One other field I&#039;ve added is the stock_on_hand value in the book table.&amp;#160; This will allow us to set a count of books available for sale and decrement them when we sell something.&lt;/p&gt;
&lt;p&gt;If we are to sell a book to a customer, we can create the customer record at any time because it won&#039;t matter if they don&#039;t buy straight away, so customer is not tied directly to a sale, so we can keep it out of our transaction.&amp;#160; When they purchase a book, however, we need to do a number of steps that have to be kept together.&amp;#160;&amp;#160; If we don&#039;t we could end up with inconsistent data.&lt;/p&gt;
&lt;p&gt;Lets go with an example.&amp;#160; I&#039;ll create a new customer and set a stock_on_hand value for Peter Temple&#039;s The Broken Shore:&lt;/p&gt;
&lt;pre&gt;INSERT INTO `customer` SET `name` = &#039;Adam Donnison&#039;,&lt;br /&gt;&amp;#160;`address1` = &#039;41 Bendigo Street&#039;,&lt;br /&gt;&amp;#160;`city` = &#039;Collingwood&#039;,&lt;br /&gt;&amp;#160;`state` = &#039;VIC&#039;, `postcode` = &#039;3066&#039;, `country` = &#039;Australia&#039;;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;UPDATE `book` SET `stock_on_hand` = 5 WHERE `id` = 1;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;Rows matched: 1  Changed: 1  Warnings: 0&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;It is important to realise at this point that every single INSERT, UPDATE or other data manipulation statement that we have performed so far has been a transaction in its own right.&amp;#160; This implicit transaction is as a result of the default value of the MySQL server variable &#039;autocommit&#039;, which is normally turned on.&amp;#160; If this is turned off we need to explictly make all queries part of a transaction.&amp;#160; More confusingly if you issue a statement that changes data, a transaction will be automatically started, but you need to commit the transaction for it to be permanently recorded in the database.&amp;#160; But let us look at the anatomy of a simple transaction.&lt;/p&gt;
&lt;p&gt;In this example we need to ensure the following happen at effectively the same time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Decrement the stock on hand value of the book sold by the quantity sold&lt;/li&gt;
&lt;li&gt;Create a purchase order entry&lt;/li&gt;
&lt;li&gt;Create an entry for each book in the order_item table&lt;/li&gt;
&lt;li&gt;Ensure the purchase order total is the total of the items in the order&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;START TRANSACTION;&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;INSERT INTO `purchase_order` SET `customer` = 1, `order_date` = NOW();&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;SET @po_number = LAST_INSERT_ID();&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;INSERT INTO `order_item` SET `purchase_order` = @po_number,&lt;br /&gt;&amp;#160;`book` = 1,&lt;br /&gt;&amp;#160;`price` = (SELECT `price` FROM `book` WHERE `id` = 1),&lt;br /&gt;&amp;#160;`quantity` = 1;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;UPDATE `purchase_order` SET `order_total` =&lt;br /&gt;&amp;#160;( SELECT SUM(`price` * `quantity`) FROM `order_item` WHERE `purchase_order` = @po_number )&lt;br /&gt;&amp;#160;WHERE `id` = @po_number;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;Rows matched: 1  Changed: 1&lt;br /&gt;&lt;br /&gt;UPDATE `book` SET `stock_on_hand` = `stock_on_hand` - 1 WHERE `id` = 1;&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;Rows matched: 1  Changed: 1  Warnings: 0&lt;br /&gt;&lt;br /&gt;COMMIT;&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;There are a few constructs here that are potentially confusing, so we need to go through each one and make sure everything is clear.&lt;/p&gt;
&lt;p&gt;First, the &lt;em&gt;SET @po_number = LAST_INSERT_ID()&lt;/em&gt; uses a MySQL function to find the ID of the record that we just inserted (the id field for the purchase_order record) and assigns it to a variable, @po_number, that we can use in subsequent queries. The reason we need to do this is to ensure we get an order_item record correctly associated with our newly created purchase order.&lt;/p&gt;
&lt;p&gt;We&#039;ve also used sub-selects. These are stand-alone select queries that are used to provide values for other queries.&amp;#160; In the first case it is a simple select to get the price field from the book table and insert it as the selling price for the order_item.&amp;#160; The second one uses an aggregation function, &lt;em&gt;SUM(`price` * `quantity`)&lt;/em&gt; to find all of our order_item records (in this case, one) and determine what the purchase order total is.&amp;#160; You are more likely to be doing this from an application so you probably wouldn&#039;t do a sum up.&amp;#160; Alternatively you could use a separate variable that you updated as you added order_item records.&amp;#160; Regardless, what we have done is a set of queries that together make up a transaction.&lt;/p&gt;
&lt;p&gt;If at any point in the transaction we decided that we had an error and we couldn&#039;t continue (perhaps we found the customer record was incorrect, or the application received an error) we can use ROLLBACK to abort the transaction and wind the database back to the point it was before we issued the START TRANSACTION.&amp;#160; By default if we were to drop the connection to the database (by closing the connection or a terminal failure in our application) or if the database server failed, any pending transaction, that is one that was STARTed but never COMMITted, would be rolled back.&lt;/p&gt;
&lt;h3&gt;Disclaimer&lt;/h3&gt;
&lt;p&gt;I am employed by &lt;a href=&quot;http://www.skysql.com/&quot;&gt;SkySQL Ab&lt;/a&gt;, which provides &lt;a href=&quot;http://www.skysql.com/services/support&quot;&gt;support&lt;/a&gt;, &lt;a href=&quot;http://www.skysql.com/services/training&quot;&gt;training&lt;/a&gt; and &lt;a href=&quot;http://www.skysql.com/services/overview&quot;&gt;services&lt;/a&gt; for  MySQL, MariaDB and Drizzle and is staffed by many ex-MySQL AB       employees.  While I try to be unbiased in all of my public opinions,  and      my  opinions are all my own and not those of my employer, I  work  for     SkySQL  because I believe in what they are doing and  therefore   cannot  be   truly  unbiased.&lt;/p&gt;
&lt;p&gt;MySQL is a registered trademark of Oracle Corporation,&amp;#160; MariaDB is a trademark of MontyProgram, and Drizzle is a trademark.&lt;/p&gt;&lt;div class=&quot;socialbutttons&quot;&gt;&lt;div class=&quot;fbiframediv sharebuttton&quot;&gt;&lt;iframe src=&quot;http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;amp;href=http://blogs.sakienvirotech.com/index.php?p=766&amp;amp;send=false&amp;amp;width=450&amp;amp;show_faces=false&amp;amp;action=like&amp;amp;colorscheme=light&amp;amp;font=arial&amp;amp;height=85&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; style=&quot;border:none; overflow:hidden; width:450px; height:85px;&quot; allowTransparency=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div class=&quot;twbutton sharebuttton&quot;&gt;&lt;a href=&quot;http://twitter.com/share&quot; class=&quot;twitter-share-button&quot; data-url=&quot;http://blogs.sakienvirotech.com/index.php?p=766&quot; data-count=&quot;horizontal&quot;&gt;Tweet&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;gplusdiv sharebuttton&quot;&gt;&lt;g:plusone href=&quot;http://blogs.sakienvirotech.com/index.php?p=766&quot;&gt;&lt;/g:plusone&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.sakienvirotech.com/index.php/random/2011/09/26/mysql-101-transactions&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://blogs.sakienvirotech.com/random&quot;&gt;Saki Envirotech Blogs&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>We've now come a long way since <a href="http://blogs.sakienvirotech.com/index.php/random/2011/09/05/mysql-101-creating-your-first">our first steps</a> at creating our online bookshop database. Now we need to start to think about how to sell the books and store details about the sales.&#160; This is the time we need to start understanding database transactions.</p>
<p>Database transactions are very similar to real world transactions. They define a set of steps required to happen together in order for a transaction to be complete.&#160; A real-world example might be that you buy a trinket from a store.&#160; You find the trinket, then take it to the counter, find out the price, hand over the cash and receive your trinket.&#160; That is a completed transaction.&#160; Should you not have the available cash, the transaction would not be able to be completed and you would need to return the item, effectively rolling back that transaction.&#160; It is not a great deal different in the database, except that the transaction can be controlled to a greater degree.</p>
<p>Before going too far, we need to build a few more tables for our database to enable us to sell our books.&#160; To make life easier I've created these tables in <a href="http://blogs.sakienvirotech.com/media/blogs/random/mysql101_bookshop_20110926.zip?mtime=1317027350">this downloadable file</a>.&#160; You can use your favourite MySQL client to create the database for the purposes of following this episode.&#160; The tables I've created are customer, purchase_order and order_item.&#160; We'll see how they work in handling a typical transaction - we can use SHOW CREATE TABLE to see how they are defined:</p>
<pre>SHOW CREATE TABLE `customer`\G<br />*************************** 1. row ***************************<br />       Table: customer<br />Create Table: CREATE TABLE `customer` (<br />  `id` int(11) NOT NULL AUTO_INCREMENT,<br />  `name` varchar(255) CHARACTER SET latin1 NOT NULL,<br />  `address1` varchar(80) CHARACTER SET latin1 NOT NULL,<br />  `address2` varchar(80) CHARACTER SET latin1 DEFAULT NULL,<br />  `postcode` varchar(8) CHARACTER SET latin1 DEFAULT NULL,<br />  `city` varchar(80) CHARACTER SET latin1 DEFAULT NULL,<br />  `country` varchar(80) CHARACTER SET latin1 DEFAULT NULL,<br />  `state` varchar(20) CHARACTER SET latin1 DEFAULT NULL,<br />  PRIMARY KEY (`id`)<br />) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8<br />1 row in set (0.00 sec)<br /><br />SHOW CREATE TABLE `purchase_order`\G<br />*************************** 1. row ***************************<br />       Table: purchase_order<br />Create Table: CREATE TABLE `purchase_order` (<br />  `id` int(11) NOT NULL AUTO_INCREMENT,<br />  `customer` int(11) NOT NULL DEFAULT '0',<br />  `order_date` datetime NOT NULL,<br />  `ship_date` datetime DEFAULT NULL,<br />  `order_total` decimal(9,2) DEFAULT NULL,<br />  PRIMARY KEY (`id`),<br />  KEY `fk_order_customer` (`customer`),<br />  CONSTRAINT `fk_order_customer` FOREIGN KEY (`customer`) REFERENCES `customer` (`id`) ON UPDATE CASCADE<br />) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8<br />1 row in set (0.00 sec)<br /><br />SHOW CREATE TABLE `order_item`\G<br />*************************** 1. row ***************************<br />       Table: order_item<br />Create Table: CREATE TABLE `order_item` (<br />  `id` int(11) NOT NULL AUTO_INCREMENT,<br />  `purchase_order` int(11) NOT NULL,<br />  `book` int(11) NOT NULL,<br />  `quantity` int(11) NOT NULL DEFAULT '0',<br />  `price` decimal(5,2) DEFAULT NULL,<br />  PRIMARY KEY (`id`),<br />  KEY `fk_item_order` (`purchase_order`),<br />  KEY `fk_item_book` (`book`),<br />  CONSTRAINT `fk_item_order` FOREIGN KEY (`purchase_order`) REFERENCES `purchase_order` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,<br />  CONSTRAINT `fk_item_book` FOREIGN KEY (`book`) REFERENCES `book` (`id`) ON UPDATE CASCADE<br />) ENGINE=InnoDB DEFAULT CHARSET=utf8<br />1 row in set (0.00 sec)<br /></pre>
<p>You'll notice a few things that may not immediately make sense.&#160; In most cases you don't want duplicate data in different tables.&#160; This is why we break out things like publisher from book, for instance.&#160; However in purchase_order we have an order_total value that could be derived from the order_item records, and similarly we have a price field in order_item that is the same as the price field in book.&#160; There is a lot of sense in doing this however.&#160; Because we are dealing with financial transactions we must ensure they can stand alone.&#160; So we need to ensure that the price of the book is not whatever the current price is, but the price it was at the&#160; time it was sold.&#160; This is why we have the price field in two places as they are not exactly the same.&#160; The order_total field is a summary data field.&#160; It means that we don't necessarily have to have a complicated multi-table join if we want to find how much a customer has bought.&#160; Summary data fields are often used to speed up common queries by simplifying them.</p>
<p>One other field I've added is the stock_on_hand value in the book table.&#160; This will allow us to set a count of books available for sale and decrement them when we sell something.</p>
<p>If we are to sell a book to a customer, we can create the customer record at any time because it won't matter if they don't buy straight away, so customer is not tied directly to a sale, so we can keep it out of our transaction.&#160; When they purchase a book, however, we need to do a number of steps that have to be kept together.&#160;&#160; If we don't we could end up with inconsistent data.</p>
<p>Lets go with an example.&#160; I'll create a new customer and set a stock_on_hand value for Peter Temple's The Broken Shore:</p>
<pre>INSERT INTO `customer` SET `name` = 'Adam Donnison',<br />&#160;`address1` = '41 Bendigo Street',<br />&#160;`city` = 'Collingwood',<br />&#160;`state` = 'VIC', `postcode` = '3066', `country` = 'Australia';<br />Query OK, 1 row affected (0.00 sec)<br /><br />UPDATE `book` SET `stock_on_hand` = 5 WHERE `id` = 1;<br />Query OK, 1 row affected (0.00 sec)<br />Rows matched: 1  Changed: 1  Warnings: 0<br /></pre>
<p>It is important to realise at this point that every single INSERT, UPDATE or other data manipulation statement that we have performed so far has been a transaction in its own right.&#160; This implicit transaction is as a result of the default value of the MySQL server variable 'autocommit', which is normally turned on.&#160; If this is turned off we need to explictly make all queries part of a transaction.&#160; More confusingly if you issue a statement that changes data, a transaction will be automatically started, but you need to commit the transaction for it to be permanently recorded in the database.&#160; But let us look at the anatomy of a simple transaction.</p>
<p>In this example we need to ensure the following happen at effectively the same time:</p>
<ul>
<li>Decrement the stock on hand value of the book sold by the quantity sold</li>
<li>Create a purchase order entry</li>
<li>Create an entry for each book in the order_item table</li>
<li>Ensure the purchase order total is the total of the items in the order</li>
</ul>
<pre>START TRANSACTION;<br />Query OK, 0 rows affected (0.00 sec)<br /><br />INSERT INTO `purchase_order` SET `customer` = 1, `order_date` = NOW();<br />Query OK, 1 row affected (0.00 sec)<br /><br />SET @po_number = LAST_INSERT_ID();<br />Query OK, 0 rows affected (0.00 sec)<br /><br />INSERT INTO `order_item` SET `purchase_order` = @po_number,<br />&#160;`book` = 1,<br />&#160;`price` = (SELECT `price` FROM `book` WHERE `id` = 1),<br />&#160;`quantity` = 1;<br />Query OK, 1 row affected (0.00 sec)<br /><br />UPDATE `purchase_order` SET `order_total` =<br />&#160;( SELECT SUM(`price` * `quantity`) FROM `order_item` WHERE `purchase_order` = @po_number )<br />&#160;WHERE `id` = @po_number;<br />Query OK, 1 row affected (0.00 sec)<br />Rows matched: 1  Changed: 1<br /><br />UPDATE `book` SET `stock_on_hand` = `stock_on_hand` - 1 WHERE `id` = 1;<br />Query OK, 1 row affected (0.00 sec)<br />Rows matched: 1  Changed: 1  Warnings: 0<br /><br />COMMIT;<br />Query OK, 0 rows affected (0.00 sec)<br /><br /></pre>
<p>There are a few constructs here that are potentially confusing, so we need to go through each one and make sure everything is clear.</p>
<p>First, the <em>SET @po_number = LAST_INSERT_ID()</em> uses a MySQL function to find the ID of the record that we just inserted (the id field for the purchase_order record) and assigns it to a variable, @po_number, that we can use in subsequent queries. The reason we need to do this is to ensure we get an order_item record correctly associated with our newly created purchase order.</p>
<p>We've also used sub-selects. These are stand-alone select queries that are used to provide values for other queries.&#160; In the first case it is a simple select to get the price field from the book table and insert it as the selling price for the order_item.&#160; The second one uses an aggregation function, <em>SUM(`price` * `quantity`)</em> to find all of our order_item records (in this case, one) and determine what the purchase order total is.&#160; You are more likely to be doing this from an application so you probably wouldn't do a sum up.&#160; Alternatively you could use a separate variable that you updated as you added order_item records.&#160; Regardless, what we have done is a set of queries that together make up a transaction.</p>
<p>If at any point in the transaction we decided that we had an error and we couldn't continue (perhaps we found the customer record was incorrect, or the application received an error) we can use ROLLBACK to abort the transaction and wind the database back to the point it was before we issued the START TRANSACTION.&#160; By default if we were to drop the connection to the database (by closing the connection or a terminal failure in our application) or if the database server failed, any pending transaction, that is one that was STARTed but never COMMITted, would be rolled back.</p>
<h3>Disclaimer</h3>
<p>I am employed by <a href="http://www.skysql.com/">SkySQL Ab</a>, which provides <a href="http://www.skysql.com/services/support">support</a>, <a href="http://www.skysql.com/services/training">training</a> and <a href="http://www.skysql.com/services/overview">services</a> for  MySQL, MariaDB and Drizzle and is staffed by many ex-MySQL AB       employees.  While I try to be unbiased in all of my public opinions,  and      my  opinions are all my own and not those of my employer, I  work  for     SkySQL  because I believe in what they are doing and  therefore   cannot  be   truly  unbiased.</p>
<p>MySQL is a registered trademark of Oracle Corporation,&#160; MariaDB is a trademark of MontyProgram, and Drizzle is a trademark.</p><div class="socialbutttons"><div class="fbiframediv sharebuttton"><iframe src="http://www.facebook.com/plugins/like.php?app_id=194259500619894&amp;href=http://blogs.sakienvirotech.com/index.php?p=766&amp;send=false&amp;width=450&amp;show_faces=false&amp;action=like&amp;colorscheme=light&amp;font=arial&amp;height=85" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:85px;" allowTransparency="true"></iframe></div><div class="twbutton sharebuttton"><a href="http://twitter.com/share" class="twitter-share-button" data-url="http://blogs.sakienvirotech.com/index.php?p=766" data-count="horizontal">Tweet</a></div><div class="gplusdiv sharebuttton"><g:plusone href="http://blogs.sakienvirotech.com/index.php?p=766"></g:plusone></div></div><div class="item_footer"><p><small><a href="http://blogs.sakienvirotech.com/index.php/random/2011/09/26/mysql-101-transactions">Original post</a> blogged on <a href="http://blogs.sakienvirotech.com/random">Saki Envirotech Blogs</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.sakienvirotech.com/index.php/random/2011/09/26/mysql-101-transactions#comments</comments>
			<wfw:commentRss>http://blogs.sakienvirotech.com/index.php/random/?tempskin=_rss2&#38;disp=comments&#38;p=766</wfw:commentRss>
		</item>
			</channel>
</rss>
