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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

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

 
本文转自 zhenjing 博客园博客,原文链接:http://www.cnblogs.com/zhenjing/archive/2011/02/15/MySQL-Transactions-Part-III.html    ,如需转载请自行联系原作者
http://www.cnblogs.com/zhenjing/archive/2011/02/15/MySQL-Transactions-Part-III.html
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
存储 关系型数据库 MySQL
在阿里云的AnalyticDB MySQL版中使用CREATE TABLE语句来创建内表
在阿里云的AnalyticDB MySQL版中使用CREATE TABLE语句来创建内表【1月更文挑战第16天】【1月更文挑战第78篇】
362 3
|
Oracle 关系型数据库 MySQL
MySQL复制表结构create table as与like的区别
MySQL复制表结构create table as与like的区别
128 0
|
6月前
|
存储 关系型数据库 MySQL
MySQL技能完整学习列表5、数据库操作——1、创建数据库和表——2、修改表结构(ALTER TABLE)
MySQL技能完整学习列表5、数据库操作——1、创建数据库和表——2、修改表结构(ALTER TABLE)
226 0
|
SQL Oracle 关系型数据库
【MySQL异常】1093 - You can‘t specify target table ‘daily_job‘ for update in FROM clause
【MySQL异常】1093 - You can‘t specify target table ‘daily_job‘ for update in FROM clause
184 0
|
6月前
|
关系型数据库 MySQL
MySQL 报错 [ERROR] [FATAL] InnoDB: Table flags are 0 in the data dictionary but the flags in file
MySQL 报错 [ERROR] [FATAL] InnoDB: Table flags are 0 in the data dictionary but the flags in file
913 0
|
关系型数据库 MySQL 数据库
对于mysql数据库delect from,truncate table,drop table, update操作的时候如何选择
对于mysql数据库delect from,truncate table,drop table, update操作的时候如何选择
189 2
|
2月前
|
SQL 关系型数据库 MySQL
MySQL 8.0报错--1118-Row size too large. The maximum row size for the used table type, not counting BLOBs,is 8126,
MySQL 8.0报错--1118-Row size too large. The maximum row size for the used table type, not counting BLOBs,is 8126,
MySQL 8.0报错--1118-Row size too large. The maximum row size for the used table type, not counting BLOBs,is 8126,
|
1月前
|
SQL 关系型数据库 MySQL
MySQL异常一之: You can‘t specify target table for update in FROM clause解决办法
这篇文章介绍了如何解决MySQL中“不能在FROM子句中指定更新的目标表”(You can't specify target table for update in FROM clause)的错误,提供了错误描述、需求说明、错误做法和正确的SQL写法。
356 0
|
SQL 存储 关系型数据库
MySQL创建数据表(CREATE TABLE语句)
MySQL创建数据表(CREATE TABLE语句)
874 0
|
5月前
|
关系型数据库 MySQL 数据库
【MySQL】MySQL数据库的delete from table和truncate table之间的区别
【MySQL】MySQL数据库的delete from table和truncate table之间的区别
605 1