LOCK TABLES
tbl_name [[AS] alias] lock_type
[, tbl_name [[AS] alias] lock_type] ...
lock_type:
READ [LOCAL]
| [LOW_PRIORITY] WRITE
UNLOCK TABLES
MySQL enables client sessions to acquire table locks explicitly for the purpose of cooperating with other sessions for access to tables, or to prevent other sessions from modifying tables during periods when a session requires exclusive access to them. A session can acquire or release locks only for itself. One session cannot acquire locks for another session or release locks held by another session.
LOCK TABLES acquires table locks for the
current thread. As of MySQL 4.0.2, to use LOCK
TABLES you must have the LOCK TABLES
privilege, and the SELECT privilege for each
table to be locked. In MySQL 3.23, you must have
SELECT, INSERT,
DELETE, and UPDATE
privileges for the tables.
MySQL enables client sessions to acquire table locks explicitly Locks may be used to emulate transactions or to get more speed when updating tables. This is explained in more detail later in this section.
UNLOCK TABLES explicitly releases any table
locks held by the current thread. Another use for UNLOCK
TABLES is to release the global read lock acquired with
FLUSH TABLES WITH READ LOCK. (You can lock all
tables in all databases with a read lock with the FLUSH
TABLES WITH READ LOCK statement. See
Section 12.5.5.2, “FLUSH Syntax”. This is a very convenient way to get
backups if you have a filesystem such as Veritas that can take
snapshots in time.)
The following discussion applies only to
non-TEMPORARY tables. LOCK
TABLES is allowed (but ignored) for a
TEMPORARY table. The table can be accessed
freely by the session within which it was created, regardless of
what other locking may be in effect. No lock is necessary because
no other session can see the table.
The following general rules apply to acquisition and release of locks by a given thread:
Table locks are acquired with LOCK TABLES.
If the LOCK TABLES statement must wait due
to locks held by other threads on any of the tables, it blocks
until all locks can be acquired.
Table locks are released explicitly with UNLOCK
TABLES.
Table locks are released implicitly under these conditions:
LOCK TABLES releases any table locks
currently held by the thread before acquiring new locks.
Beginning a transaction (for example, with START
TRANSACTION) implicitly performs an
UNLOCK TABLES. (Additional information
about the interaction between table locking and
transactions is given later in this section.)
If a client connection drops, the server releases table locks held by the client. If the client reconnects, the locks will no longer be in effect. In addition, if the client had an active transaction, the server rolls back the transaction upon disconnect, and if reconnect occurs, the new session begins with autocommit enabled. For this reason, clients may wish to disable auto-reconnect. With auto-reconnect in effect, the client is not notified if reconnect occurs but any table locks or current transaction will have been lost. With auto-reconnect disabled, if the connection drops, an error occurs for the next statement issued. The client can detect the error and take appropriate action such as reacquiring the locks or redoing the transaction. See Section 17.2.13, “Controlling Automatic Reconnect Behavior”.
If you use ALTER TABLE on a locked table, it
may become unlocked. See Section A.1.7.1, “Problems with ALTER TABLE”.
A table lock protects only against inappropriate reads or writes
by other clients. The client holding the lock, even a read lock,
can perform table-level operations such as DROP
TABLE. Truncate operations are not transaction-safe, so
an error occurs if the client attempts one during an active
transaction or while holding a table lock.
When you use LOCK TABLES, you must lock all
tables that you are going to use in your statements. While the
locks obtained with a LOCK TABLES statement are
in effect, you cannot access any tables that were not locked by
the statement. If you lock a view, LOCK TABLES
adds all base tables used in the view to the set of tables to be
locked and locks them automatically.
You cannot refer to a locked table multiple times in a single query using the same name. Use aliases instead, and obtain a separate lock for the table and each alias:
mysql>LOCK TABLE t WRITE, t AS t1 READ;mysql>INSERT INTO t SELECT * FROM t;ERROR 1100: Table 't' was not locked with LOCK TABLES mysql>INSERT INTO t SELECT * FROM t AS t1;
The error occurs for the first INSERT because
there are two references to the same name for a locked table. The
second INSERT succeeds because the references
to the table use different names.
If your statements refer to a table by means of an alias, you must lock the table using that same alias. It does not work to lock the table without specifying the alias:
mysql>LOCK TABLE t READ;mysql>SELECT * FROM t AS myalias;ERROR 1100: Table 'myalias' was not locked with LOCK TABLES
Conversely, if you lock a table using an alias, you must refer to it in your statements using that alias:
mysql>LOCK TABLE t AS myalias READ;mysql>SELECT * FROM t;ERROR 1100: Table 't' was not locked with LOCK TABLES mysql>SELECT * FROM t AS myalias;
If a thread obtains a READ lock on a table,
that thread (and all other threads) can only read from the table.
If a thread obtains a WRITE lock on a table,
only the thread holding the lock can write to the table (that
thread can also read from the table); other threads are blocked
from reading or writing the table until the lock has been
released.
The difference between READ and READ
LOCAL is that READ LOCAL allows
non-conflicting INSERT statements (concurrent
inserts) to execute while the lock is held. However, READ
LOCAL cannot be used if you are going to manipulate the
database using processes external to the server while you hold the
lock. For InnoDB tables, READ
LOCAL is the same as READ as of MySQL
4.1.15. (Before that, READ LOCAL essentially
does nothing: It does not lock the table at all, so for
InnoDB tables, the use of READ
LOCAL is deprecated because a plain consistent-read
SELECT does the same thing, and no locks are
needed.)
WRITE locks normally have higher priority than
READ locks to ensure that updates are processed
as soon as possible. This means that if one thread obtains a
READ lock and then another thread requests a
WRITE lock, subsequent READ
lock requests wait until the thread that requested the
WRITE lock has obtained the lock and released
it. A request for a LOW_PRIORITY WRITE lock, by
contrast, allows subsequent READ lock requests
by other threads to be satisfied first if they occur while the
LOW_PRIORITY WRITE request is waiting. You
should use LOW_PRIORITY WRITE locks only if you
are sure that eventually there will be a time when no threads have
a READ lock. For InnoDB
tables in transactional mode (autocommit = 0), a waiting
LOW_PRIORITY WRITE lock acts like a regular
WRITE lock and causes subsequent
READ lock requests to wait.
LOCK TABLES works as follows:
Sort all tables to be locked in an internally defined order. From the user standpoint, this order is undefined.
If a table is to be locked with a read and a write lock, put the write lock request before the read lock request.
Lock one table at a time until the thread gets all locks.
This policy ensures that table locking is deadlock free. There
are, however, other things you need to be aware of about this
policy: If you are using a LOW_PRIORITY WRITE
lock for a table, it means only that MySQL waits for this
particular lock until there are no other threads that want a
READ lock. When the thread has gotten the
WRITE lock and is waiting to get the lock for
the next table in the lock table list, all other threads wait for
the WRITE lock to be released. If this becomes
a serious problem with your application, you should consider
converting some of your tables to transaction-safe tables.
LOCK TABLES and UNLOCK
TABLES interact with the use of transactions as follows:
LOCK TABLES is not transaction-safe and
implicitly commits any active transaction before attempting to
lock the tables.
UNLOCK TABLES implicitly commits any active
transaction, but only if LOCK TABLES has
been used to acquire table locks. For example, in the
following set of statements, UNLOCK TABLES
releases the global read lock but does not commit the
transaction because no table locks are in effect:
FLUSH TABLES WITH READ LOCK; START TRANSACTION; SELECT ... ; UNLOCK TABLES;
Beginning a transaction (for example, with START
TRANSACTION) implicitly commits any current
transaction and releases existing locks.
Other statements that implicitly cause transactions to be committed do not release existing locks. For a list of such statements, see Section 12.4.3, “Statements That Cause an Implicit Commit”.
The correct way to use LOCK TABLES and
UNLOCK TABLES with transactional tables,
such as InnoDB tables, is to begin a
transaction with SET AUTOCOMMIT = 0 (not
START TRANSACTION) followed by
LOCK TABLES, and to not call
UNLOCK TABLES until you commit the
transaction explicitly. When you call LOCK
TABLES, InnoDB internally takes
its own table lock, and MySQL takes its own table lock.
InnoDB releases its internal table lock at
the next commit, but for MySQL to release its table lock, you
have to call UNLOCK TABLES. You should not
have AUTOCOMMIT = 1, because then
InnoDB releases its internal table lock
immediately after the call of LOCK TABLES,
and deadlocks can very easily happen. Starting from 4.1.9,
InnoDB does not acquire the internal table
lock at all if AUTOCOMMIT=1, to help old
applications avoid unnecessary deadlocks.
ROLLBACK does not release table locks.
FLUSH TABLES WITH READ LOCK acquires a
global read lock and not table locks, so it is not subject to
the same behavior as LOCK TABLES and
UNLOCK TABLES with respect to table locking
and implicit commits. See Section 12.5.5.2, “FLUSH Syntax”.
You can safely use KILL to terminate a thread
that is waiting for a table lock. See Section 12.5.5.3, “KILL Syntax”.
You should not lock any tables that you are
using with INSERT DELAYED because in that case
the INSERT is performed by a separate thread.
Normally, you do not need to lock tables, because all single
UPDATE statements are atomic; no other thread
can interfere with any other currently executing SQL statement.
However, there are a few cases when locking tables may provide an
advantage:
If you are going to run many operations on a set of
MyISAM tables, it is much faster to lock
the tables you are going to use. Locking
MyISAM tables speeds up inserting,
updating, or deleting on them because MySQL does not flush the
key cache for the locked tables until UNLOCK
TABLES is called. Normally, the key cache is flushed
after each SQL statement.
The downside to locking the tables is that no thread can
update a READ-locked table (including the
one holding the lock) and no thread can access a
WRITE-locked table other than the one
holding the lock.
If you are using tables for a non-transactional storage
engine, you must use LOCK TABLES if you
want to ensure that no other thread modifies the tables
between a SELECT and an
UPDATE. The example shown here requires
LOCK TABLES to execute safely:
LOCK TABLES trans READ, customer WRITE; SELECT SUM(value) FROM trans WHERE customer_id=some_id; UPDATE customer SET total_value=sum_from_previous_statementWHERE customer_id=some_id; UNLOCK TABLES;
Without LOCK TABLES, it is possible that
another thread might insert a new row in the
trans table between execution of the
SELECT and UPDATE
statements.
You can avoid using LOCK TABLES in many cases
by using relative updates (UPDATE customer SET
)
or the value=value+new_valueLAST_INSERT_ID() function.
See Section 1.8.5.3, “Transactions and Atomic Operations”.
You can also avoid locking tables in some cases by using the
user-level advisory lock functions
GET_LOCK() and
RELEASE_LOCK(). These locks are
saved in a hash table in the server and implemented with
pthread_mutex_lock() and
pthread_mutex_unlock() for high speed. See
Section 11.10.4, “Miscellaneous Functions”.
See Section 7.3.1, “Internal Locking Methods”, for more information on locking policy.

User Comments
WARNING
WARNING
WARNING
Carefully notice the "LOCK TABLES causes an implict commit" and "A new transaction implictly does UNLOCK TABLES" above, as that means "MySQL will implictly make your code run and usually work, just including the race condition you very carefully wrote the code to avoid."
WARNING
WARNING
WARNING
Note that while you are allowed to drop a table that you have a lock on, you can not subsequently create the table. Attempts to create the table without first issueing unlock tables results in a "table not locked" error. Therefore, you can't use lock tables to process data through several staging tables where you would drop and create the intermidiate tables. Truncate also won't work, as stated in the manual. The only option that will work is to delete from the table, but this is a slow operation.
It appears that tables affected by triggers need to be locked - even if the none of the trigger conditions evalute to true.
1100: Table 'tblQuestionsArchive' was not locked with LOCK TABLES - No link, or no result set created. Query: UPDATE validation NATURAL JOIN tblResponses NATURAL JOIN tblQuestions, tblCodes
SET br = CodeSASBrand
WHERE QuestionCodingName = 'br'
AND tblCodes.CodeID = tblResponses.CodeID
The column "br" is in the validation temp table. Updates on tblQuestions tigger an insert into tblQuestionsArchive-
CREATE TRIGGER questionUpdate AFTER UPDATE ON tblQuestions
FOR EACH ROW BEGIN
IF NEW.ParentQuestionID != OLD.ParentQuestionID OR
[...SNIP...]
THEN
INSERT INTO tblQuestionsArchive SET
QuestionID=OLD.QuestionID,
ParentQuestionID=OLD.ParentQuestionID,
[...SNIP...]
QuestionArchiveDate=UNIX_TIMESTAMP();
END IF;
END
//
Add your own comment.