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
| IN SHARE MODE [NOWAIT]
| IN EXCLUSIVE MODE [NOWAIT]
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 explicitly acquires
non-transactional or transactional table locks for the current
client session.
Table locks can be acquired for base tables or views. You must
have the LOCK TABLES privilege, and
the SELECT privilege for each
object to be locked. (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.)
MySQL 6.0 supports non-transactional and transactional locks. These are intended for use in non-transactional or transactional context, respectively. Non-transactional 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 non-transactional table locks
held by the current session. Transactional table locks are
released by ending the current transaction.
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.7.3, “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.)
A table lock protects only against inappropriate reads or writes
by other sessions. The session holding the lock can perform
table-level operations such as DROP
TABLE. Truncate operations are not transaction-safe, so
an error occurs if the session attempts one during an active
transaction or while holding a table lock.
As of MySQL 6.0.3, DROP TABLE is
allowed only if you have acquired a WRITE lock
with LOCK TABLES, or if you hold no
locks, or if the table is a TEMPORARY table.
(Previously, if other tables were locked, you could drop a table
while holding a read lock or no lock for it, which could lead to
deadlocks between sessions. The current stricter behavior means
that some usage scenarios will fail when previously they did not.)
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.
Rules for Lock Acquisition
To acquire non-transactional or transactional table locks within
the current session, use the LOCK
TABLES statement.
Rules for acquisition of non-transactional locks. MySQL supports non-transactional read and write table locks. These can be acquired in non-transactional contexts (that is, when autocommit is enabled).
READ [LOCAL] lock:
The session that holds the lock can read the table (but not write it).
Multiple sessions can acquire a READ lock
for the table at the same time.
Other sessions can read the table without explicitly acquiring
a READ lock.
The LOCAL modifier enables concurrent
inserts by other sessions to proceed while the lock is held.
(See Section 7.3.3, “Concurrent Inserts”.)
[LOW_PRIORITY] WRITE lock:
The session that holds the lock can read and write the table.
Only the session that holds the lock can access the table. No other session can access it until the lock is released.
Lock requests for the table by other sessions block while the
WRITE lock is held.
The LOW_PRIORITY modifier affects lock
scheduling if the WRITE lock request must
wait, as described later.
A session that requires non-transactional locks must acquire all
the locks that it needs in a single LOCK
TABLES statement.
A session that holds non-transactional locks can access only the locked tables while the locks are held.
A session cannot hold non-transactional locks and use transactions at the same time. Acquisition of a non-transactional lock implicitly commits any active transaction for the current session, and beginning a transaction implicitly releases all locks held by the session. (Additional information about the interaction between table locking and transactions is given later in this section.)
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.
WRITE locks normally have higher priority than
READ locks to ensure that updates are processed
as soon as possible. This means that if one session obtains a
READ lock and then another session requests a
WRITE lock, subsequent READ
lock requests wait until the session 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 sessions 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 sessions
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 for
non-transactional locks:
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 session 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 sessions that want a
READ lock. When the session has gotten the
WRITE lock and is waiting to get the lock for
the next table in the lock table list, all other sessions 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.
Rules for acquisition of transactional locks. As of MySQL 6.0.3, MySQL supports transactional shared and exclusive table locks that do not commit transactions automatically. These locks apply only for transactional storage engines that support them and only during a transaction (that is, when autocommit is disabled).
Currently, only InnoDB supports transactional
locks. For other transactional storage engines or for
non-transactional storage engines, requests for transactional
locks are converted to requests for non-transactional locks, as
described later.
IN SHARE MODE [NOWAIT] lock:
The session that holds the lock can read the table, and can also write the table under some circumstances.
Multiple sessions can acquire an IN SHARE
MODE lock for the table at the same time.
Other sessions can read the table without explicitly acquiring
an IN SHARE MODE lock.
IN EXCLUSIVE MODE [NOWAIT] lock:
The session that holds the lock can read and write the table.
Only the session that holds the lock can access the table. No other session can access it until the lock is released.
Lock requests for the table by other sessions block while the
IN EXCLUSIVE MODE lock is held.
By default, LOCK TABLES waits if
all requested locks cannot be acquired immediately (for example,
if the requests cannot be granted due to locks held by other
sessions). For transactional locks, the NOWAIT
modifier can be given. The intent of this modifier is that the
lock request will fail with an error if the lock cannot be
acquired immediately, but NOWAIT is not
currently implemented by any storage engine.
A session that requires transactional locks need not acquire them
all in a single LOCK TABLES
statement. A session can acquire transactional locks sequentially
with multiple LOCK TABLES
statements, each one adding new locks to the current set of locks.
It is even possible to acquire additional transactional locks on a
table for which the session already holds transactional locks.
A session that holds transactional locks can access non-locked tables while the locks are held.
Transactional locks are not specific to reading or writing. Both operations are allowed to the holder of the lock, whether it is shared or exclusive, with some restrictions:
The holder of an IN EXCLUSIVE MODE lock has
exclusive access to read and write the table and no other
session can lock the table.
The holder of an IN SHARE MODE lock has
shared access to read the table. The lock holder can also
write the table, as long as no other session also has a shared
lock for the table. If a session that holds a shared lock has
written to the table, no other session can acquire a lock for
the table.
Transactional locks do not apply if a session is not in
transactional context; that is, when autocommit mode is enabled
because the session has not used
START
TRANSACTION or SET autocommit = 0. In
this case, the lock is released as soon as the
LOCK TABLES statement ends, which
makes the statement almost a non-operation. The only difference is
that the request blocks if it must wait for an existing lock to be
released, but then the new lock is immediately released.
For LOCK TABLES statements that
involve a mix of non-transactional and transactional locks,
requests for transactional locks are converted to requests for
non-transactional locks. This occurs because a session can hold
multiple locks at a time, but cannot hold a mix of
non-transactional and transactional locks:
It is permissible to hold multiple READ or
WRITE locks at the same time.
It is permissible to hold multiple IN SHARE
MODE or IN EXCLUSIVE MODE locks
at the same time.
It is not possible to hold a READ or
WRITE lock at the same time as an
IN SHARE MODE or IN EXCLUSIVE
MODE lock.
For example, these operations are allowed because they request only non-transactional locks, or only transactional locks:
LOCK TABLES t1 READ, t2 WRITE, t3 READ; LOCK TABLES t4 IN SHARE MODE, t5 IN EXCLUSIVE MODE, t6 IN SHARE MODE;
But these operations cannot be processed as requested because they attempt to acquire a mix of non-transactional and transactional locks:
LOCK TABLES t1 READ, t2 IN SHARE MODE; LOCK TABLES t3 WRITE, t4 IN EXCLUSIVE MODE;
For the latter statements, the requests for transactional locks are converted to requests for non-transactional locks. Lock conversions may succeed or fail, as described later.
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;
Rules for Lock Release
When the table locks held by a session are released, they are all released at the same time. A session can release its locks explicitly, or locks may be released implicitly under certain conditions.
Rules for lock release when a session holds non-transactional locks:
A session can release its locks explicitly with
UNLOCK
TABLES.
If a session issues a LOCK
TABLES statement to acquire a lock while already
holding non-transactional locks, its existing locks are
released implicitly before the new locks are granted.
If a session begins a transaction, an implicit
UNLOCK
TABLES is performed, which causes existing locks to
be released.
If the connection for a client session terminates, the server releases the session's locks.
Rules for lock release when a session holds transactional locks:
UNLOCK
TABLES does not release
transactional locks.
Ending a transaction explicitly, by either
COMMIT or
ROLLBACK,
releases existing locks.
Beginning a transaction implicitly commits the current transaction, which releases existing locks.
If the session issues a LOCK
TABLES request for a non-transactional lock, that
implicitly commits the current transaction, which releases
existing locks.
Any other statement that causes an implicit commit releases the existing locks. For a list, see Section 12.4.3, “Statements That Cause an Implicit Commit”.
If the connection for a client session terminates, the server implicitly rolls back the current transaction and releases the session's locks.
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 20.8.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”.
Rules for Transactional Lock Conversion
Under some circumstances, a request for a transactional lock cannot be granted:
A session cannot use LOCK
TABLES to simultaneously acquire transactional and
non-transactional locks.
A session cannot acquire transactional locks while currently holding non-transactional locks.
A session cannot acquire transactional locks for storage engines that do not support them:
The table to be locked is non-transactional (for example,
MyISAM).
The table to be locked is transactional but the storage
engine does not support transactional locks. (Currently,
only InnoDB supports transactional
locks.)
When a transactional lock cannot be granted for the preceding reasons, the request is converted to a request for a non-transactional lock. The conversion is handled as follows:
If strict SQL mode is enabled, lock conversion is prohibited and an error occurs.
mysql>SET sql_mode = 'STRICT_TRANS_TABLES,STRICT_ALL_TABLES';Query OK, 0 rows affected (0.00 sec) mysql>LOCK TABLES t1 READ, t2 IN SHARE MODE;ERROR 1615 (HY000): Cannot convert to non-transactional lock in strict mode on 't2'
Otherwise, conversion occurs and a warning is generated.
mysql>SET sql_mode = '';Query OK, 0 rows affected (0.00 sec) mysql>LOCK TABLES t1 READ, t2 IN SHARE MODE;Query OK, 0 rows affected, 1 warning (0.00 sec) mysql>SHOW WARNINGS;+---------+------+---------------------------------------------+ | Level | Code | Message | +---------+------+---------------------------------------------+ | Warning | 1614 | Converted to non-transactional lock on 't2' | +---------+------+---------------------------------------------+ 1 row in set (0.00 sec)
When conversion occurs, IN SHARE MODE is
converted to READ and IN EXCLUSIVE
MODE is converted to WRITE.
The following notes describe what happens when a session already holds one type of lock and then requests another lock:
Session holds a non-transactional lock, and then requests a non-transactional lock:
An implicit
UNLOCK
TABLES occurs, which releases the existing
non-transactional lock.
The new non-transactional lock is granted.
Session holds a non-transactional lock, and then requests a transactional lock:
The request is converted to a request for a non-transactional lock.
An implicit
UNLOCK
TABLES occurs, which releases the existing
non-transactional lock.
The new non-transactional lock is granted.
Session holds a transactional lock, and then requests a transactional lock
The new transactional lock is granted without releasing the existing transactional lock.
Session holds a transactional lock, and then requests a non-transactional lock
An implicit commit occurs, which releases the existing transactional lock.
The new non-transactional lock is granted.
Thus, the following sequence results in insertion of a row, even though there is no explicit commit:
DROP TABLE IF EXISTS t; CREATE TABLE t (i INT) ENGINE = InnoDB; START TRANSACTION; LOCK TABLE t IN EXCLUSIVE MODE; INSERT INTO t VALUES(1); LOCK TABLE t READ; SELECT * FROM t;
Interaction of Table Locking and Transactions
LOCK TABLES and
UNLOCK
TABLES interact with the use of transactions as follows:
When used to acquire non-transactional locks,
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 non-transactional 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 non-transactional 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 non-tranactional locks and 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 non-transactional 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.7.3, “FLUSH Syntax”.
Other Table-Locking Notes
You can safely use KILL to
terminate a session that is waiting for a table lock. See
Section 12.5.7.4, “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.
For some operations, system tables in the mysql
database must be accessed. For example, the
HELP statement requires the
contents of the server-side help tables, and
CONVERT_TZ() might need to read the
time zone tables. The server implicitly locks the system tables
for reading as necessary so that you need not lock them
explicitly. These tables are treated as just described:
mysql.help_category mysql.help_keyword mysql.help_relation mysql.help_topic mysql.proc mysql.time_zone mysql.time_zone_leap_second mysql.time_zone_name mysql.time_zone_transition mysql.time_zone_transition_type
If you want to explicitly place a WRITE lock on
any of those tables with a LOCK
TABLES statement, the table must be the only one locked;
no other table can be locked with the same statement.
Normally, you do not need to lock tables, because all single
UPDATE statements are atomic; no
other session 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 session can
update a READ-locked table (including the
one holding the lock) and no session 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 session
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 session 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.11.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.