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.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.)
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 28.2.13, “Controlling Automatic Reconnect 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.2, “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.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.
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.8.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
//
Add your own comment.