您的位置:首页 > 数据库 > MySQL

MySQL Transactions, Part III - BDB Tables, Table locking and Savepoints

2011-02-15 13:05 447 查看
September 21, 2004

MySQL Transactions, Part III - BDB Tables, Table locking and Savepoints

By Ian Gilfillan

BDB Transactions

The previous two columns
in this series have covered general
transactions with InnoDB tables and transaction
isolation levels. This month, we look at transactions with other table
types, specifically BDB tables, and all other table types, including the
default MyISAM table type.

BDB Tables are not that
commonly used. Most tables tend to be either the default MyISAM table type, or,
for those specifically wanting ACID compliance, InnoDB. BDB (standing for BerkeleyDB)
is the poor relation as far as MySQL goes, a table type that precedes InnoDB,
and was included for its transactional capability, but which never achieved as
much popularity. The BDB format itself is stable (it is supplied by a third
party - Sleepycat Software), but the MySQL interface to it is not yet
'production'.

mysql>CREATE TABLE bdb_table(f INT) TYPE = BDB

First up, note a very
important difference in the default behavior of BDB tables compared with InnoDB
tables. From one connection, run the following:

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO bdb_table VALUES(1);
Query OK, 1 row affected (0.00 sec)

From a
second connection, see what the table contains:

mysql> SELECT * FROM bdb_table;

Note that the connection
hangs - it is waiting for the other connection to COMMIT its transaction before
returning a result. Remember that InnoDB tables returned a result based upon
the data before any other uncommitted transactions had begun. Commit the
transaction, and the result appears:

Connection
1:

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

Connection
2:

mysql> SELECT * FROM bdb_table;
+------+
| f    |
+------+
|    1 |
+------+
1 row in set (7.08 sec)

This default behavior
could lead to performance problems in your applications, and is one of the
reasons for InnoDB's greater popularity.

Autocommit

MySQL's default behavior
is to automatically commit statements not explicitly wrapped in a transaction.
As we saw here
with InnoDB tables, this means any statement that does not have a BEGIN
preceding it will be immediately carried out (as if you were using the
non-transactional MyISAM table type), as demonstrated below.

From
Connection 1:

mysql> INSERT INTO bdb_table VALUES(2);
Query OK, 1 row affected (0.00 sec)

Connection
2:

mysql> SELECT * FROM bdb_table;
+------+
| f    |
+------+
|    1 |
|    2 |
+------+
2 rows in set (0.00 sec)

You can circumvent this behavior
by setting AUTOCOMMIT to 0, in which case all statements are treated as if a
BEGIN statement precedes them, for example:

Connection
1:

mysql> SET AUTOCOMMIT=0;
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO bdb_table VALUES(3);
Query OK, 1 row affected (0.00 sec)

Connection
2:

mysql> SELECT * FROM bdb_table;

Again the thread hangs,
waiting for a commit from the first connection.

Connection
1:

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

Connection
2:

mysql> SELECT * FROM bdb_table;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

Of course, BDB tables
also use the ROLLBACK statement to return the data back to the status it was in
prior to the transaction:

Connection
1:

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO bdb_table VALUES(4);
Query OK, 1 row affected (0.01 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM bdb_table; +------+ | f | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.00 sec)


Table locking for all table types

InnoDB and BDB tables
both make use of row level locking, whereby only the row/s being manipulated
are locked. This means that other rows can still be manipulated, reducing the
risk of contention, but is also a less optimal process than table level locking
if most of the queries are SELECT's. MyISAM tables do not have row-locking,
which is why they are not a great choice if the application has a high ration
of INSERT's or UPDATE's to SELECT's. However, all table types can make use of table-locking,
using the LOCK TABLE statement.

Since this is the only
kind of locking available to MyISAM tables, let's create a MyISAM table to test
on:

mysql> CREATE TABLE myisam_table(f INT);
Query OK, 0 rows affected (0.01 sec)

There are two main kinds
of locks - read locks and write locks. A read lock only allows
reads on the table, not writes, while a write lock only allows that connection
to read and write - all other connections are blocked. Let's see these in
action:

Connection
1:

mysql> LOCK TABLE myisam_table READ;
Query OK, 0 rows affected (0.00 sec)

Connection
2:

mysql> INSERT INTO myisam_table VALUES(1);

The second connection
hangs, waiting for the table to be unlocked.

Connection
1:

mysql> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)

Connection
2:

mysql> INSERT INTO myisam_table VALUES(1);
Query OK, 1 row affected (1 min 16.34 sec)

However, a read from the
second connection is processed immediately:

Connection
1:

mysql> LOCK TABLE myisam_table READ;
Query OK, 0 rows affected (0.00 sec)

Connection
2:

mysql> SELECT * FROM myisam_table;
+------+
| f    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

Connection
1:

mysql> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)

Let's try the same
statements with a write lock.

Connection
1:

mysql> LOCK TABLE myisam_table WRITE;
Query OK, 0 rows affected (0.01 sec)

Connection
2:

mysql> SELECT * FROM myisam_table;

The connection hangs,
waiting for the lock to be released.

Connection
1:

mysql> UNLOCK TABLE;
Query OK, 0 rows affected (0.01 sec)

Connection
2:

mysql> SELECT * FROM myisam_table;
+------+
| f    |
+------+
|    1 |
+------+
1 row in set (6.22 sec)

If you have been thinking
about this a bit, you may wonder what happens if the connection that creates a
READ lock attempts to INSERT a record. Since this is forbidden on a read lock
even to the originating connection, and if the connection had to wait, there
would be deadlock since it would then be unable to release the lock, MySQL
returns an immediate error.

mysql> LOCK TABLE myisam_table READ;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO myisam_table VALUES(2);
ERROR 1099: Table 'myisam_table' was locked with a READ lock and can't be updated

mysql> UNLOCK TABLE; Query OK, 0 rows affected (0.00 sec)

Locking priority

Write locks have a higher
priority than read locks. A write lock will always be obtained ahead of any
prior waiting read locks. Let's demonstrate this:

Connection
1:

mysql> LOCK TABLE myisam_table WRITE;
Query OK, 0 rows affected (0.00 sec)

Connection
2:

mysql> LOCK TABLE myisam_table READ;

The connection hangs,
waiting for the earlier lock to be released.

Connection
3:

mysql> LOCK TABLE myisam_table WRITE;

Now there are two locks
waiting, a read lock, and a write lock requested after the read lock. When we
release the first lock, the lock from the third connection, since it is a
higher precedence write lock, is obtained.

Connection
1:

mysql> UNLOCK TABLE;
Query OK, 0 rows affected (0.00 sec)

Connection 2 is still
waiting, but connection 3 is ready for action again:

mysql> LOCK TABLE myisam_table WRITE;
Query OK, 0 rows affected (5.52 sec)

mysql> UNLOCK TABLE; Query OK, 0 rows affected (0.00 sec)

Only now is the second
connection's lock obtained. It does not take much imagination to understand why
table locking can lead to performance implications if there are many write
locks.

Sometimes you genuinely
want a write lock to have a lower priority than a read lock. An example we use
at Independent Online is the article
tracker. Every article read is tracked, but the INSERT statement is a lower
priority than the read, which of course impacts a reader. Using the same MyISAM
table and the same set of locks as before except that the third connection is a
low priority lock, let's examine what happens.

Connection 1:

mysql> LOCK TABLE myisam_table WRITE;
Query OK, 0 rows affected (0.00 sec)

Connection
2:

mysql> LOCK TABLE myisam_table READ;

The connection hangs,
waiting for the earlier lock to be released.

Connection
3:

mysql> LOCK TABLE myisam_table LOW_PRIORITY WRITE;

Connection
1:

mysql> UNLOCK TABLE;
Query OK, 0 rows affected (0.00 sec)

This time, Connection 2
is obtained, while the write lock in connection 3 is still waiting.

Connection 2:

mysql> LOCK TABLE myisam_table READ;
Query OK, 0 rows affected (3 min 8.29 sec)

mysql> UNLOCK TABLE; Query OK, 0 rows affected (0.00 sec)

Connection
3:

mysql> LOCK TABLE myisam_table LOW_PRIORITY WRITE;
Query OK, 0 rows affected (2 min 12.23 sec)

mysql> UNLOCK TABLE; Query OK, 0 rows affected (0.00 sec)

Savepoints

Finally,
for this month, we will go back to InnoDB tables, and examine a recent addition
to MySQL - savepoints. These allow you to rollback part of a transaction,
rather than the all or nothing approach usually found with transactions. Savepoints
only work with InnoDB tables - for those who have not been following the
series, you can recreate the table as it is with the following statements
(though the records are not really necessary):

mysql> CREATE TABLE t (f INT) TYPE = InnoDB;
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO t values (1),(2),(3),(4),(55),(6),(7),(88);
Query OK, 8 rows affected (0.00 sec)
Records: 8  Duplicates: 0  Warnings: 0

Inside the same
transaction, we will insert two new records, one before the savepoint, and one
after:

mysql> INSERT INTO t VALUES(9);
Query OK, 1 row affected (0.05 sec)

mysql> SAVEPOINT x;
Query OK, 0 rows affected (0.06 sec)

mysql> INSERT INTO t VALUES(10);
Query OK, 1 row affected (0.00 sec)

mysql> ROLLBACK TO SAVEPOINT x;
Query OK, 0 rows affected (0.06 sec)

mysql> SELECT * FROM t;
+------+
| f    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|   55 |
|    6 |
|    7 |
|   88 |
|    9 |
+------+
9 rows in set (0.00 sec)

The first insert has been
performed - effectively a savepoint could also be termed COMMIT UNTIL, so
anything before the savepoint is now committed. The second insert, after the savepoint,
is rolled back.

That concludes the series
on transactions. I hope that you have gotten a taste for how MySQL handles
them, and some of its quirks, but as always, there is no better way to learn
than diving in and making all the mistakes yourself. Good luck.

MySQL Transactions, Part III - BDB Tables, Table locking and Savepoints
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐