The world's most popular open source database
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. It locks base tables or (as of MySQL
5.0.6) views. (For view locking, LOCK
TABLES adds all base tables used in the view to the set
of tables to be locked and locks them automatically.) To use
LOCK TABLES, you must have the
LOCK TABLES privilege, and the
SELECT privilege for each object to
be locked.
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.6.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 19.7.13, “Controlling Automatic Reconnection Behavior”.
If you use ALTER TABLE on a
locked table, it may become unlocked. See
Section B.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 5.0.13. (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. 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.6.2, “FLUSH Syntax”.
You can safely use KILL to
terminate a thread that is waiting for a table lock. See
Section 12.5.6.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.7.5.2, “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
//
It is not stated on this page, but "LOCK" is not allowed from within a stored procedure.
I had just had a similar error and I found out that I wrote in the table name wrong and the table didn't exist. It was a confusing error message to spit out, and combined that I'm fairly new to triggers in MYSQL it put me on the wrong path to solving the problem for a short while.
Add your own comment.