In our last episode we looked at transactions and how to create them. In this episode I'll look at some of the implications of transactions, especially in a web application.
Transactions and Replication
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. What gets transferred are the changes that are made to your tables and data. So what about rolled-back (aborted) transactions? 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. Indeed they are not replicated. Only completed transactions are.
I briefly mentioned that there is an autocommit setting that means that without using a transaction block, every query becomes its own transaction. In the light of replication this makes a lot of sense.
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. In general this means that the second transaction will block until the first transaction is either committed or rolled back. For web, having a locked resource hanging around for any length of time is a real killer. This can be avoided by keeping transactions as short as possible, and to be careful of using range-based operations.
Let us say that we have two people trying to buy the same book. 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. They are:
- Create a purchase order record
- Create purchase order item records for the book(s) purchased
- Update the summary field on the purchase order record
- Decrement the stock count for the book(s) purchased
If you look at those steps, you could see how a web application designer might get themselves into trouble. 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. This would be a complete disaster. 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. This is where you need to be very aware of what the logic of the application is and how to bound the transactions.
In the above case we could handle this in a number of ways. 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. Another way would be to separate the actual purchase order creation from the selection process. 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.
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.
Short Circuited Transactions
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. 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. DDL statements, in general, cannot be rolled back as they run in their own transaction.
More information on the caveats with transactions can be found in the online manual reference.
I am employed by SkySQL Ab, which provides support, training and services 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.
MySQL is a registered trademark of Oracle Corporation, MariaDB is a trademark of MontyProgram, and Drizzle is a trademark.