LOCK TABLES
tbl_name [[AS] alias] lock_type
[, tbl_name [[AS] alias] lock_type] ...
lock_type:
READ [LOCAL]
| [LOW_PRIORITY] WRITE
UNLOCK TABLES
LOCK TABLES acquires table locks for the
current thread. It locks base tables but not views. To use
LOCK TABLES, you must have the LOCK
TABLES privilege, and the SELECT
privilege for each table to be locked.
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
read locks 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 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 the
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. 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 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. See Section 27.2.13, “Controlling Automatic Reconnect Behavior”.
One thread cannot release locks held by another thread.
If you use ALTER TABLE on a locked table,
it may become unlocked. See
Section B.1.7.1, “Problems with ALTER TABLE”.
The main reasons to use LOCK TABLES are to
emulate transactions or to get more speed when updating tables.
This is explained in more detail later in this section.
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. Because LOCK TABLES will
not lock views, if the operation that you are performing uses
any views, you must also lock all base tables on which those
views depend.
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.
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.
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 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 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 transactional tables
as follows:
LOCK TABLES is not transaction-safe and
implicitly commits any active transaction before attempting
to lock the tables. Also, beginning a transaction (for
example, with START TRANSACTION)
implicitly performs an UNLOCK TABLES.
(See Section 12.4.3, “Statements That Cause an Implicit Commit”.)
UNLOCK TABLES implicitly commits any
active transaction, but only if any tables have been locked
with LOCK TABLES.
The correct way to use LOCK TABLES and
UNLOCK TABLES with transactional tables,
such as InnoDB tables, is to set
AUTOCOMMIT = 0 and not to 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. Note
that we do not acquire the InnoDB
internal table lock at all if
AUTOCOMMIT=1, to help old applications
avoid unnecessary deadlocks.
ROLLBACK does not release MySQL's
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.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.
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. Before MySQL 5.1.17, to perform such
operations while a LOCK TABLES statement is
in effect, you must also lock the requisite system tables
explicitly or a lock error occurs. As of 5.1.17, 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 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.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.
If you are getting this error from a trigger (or stored procedure executed from a trigger), the problem may have nothing to do with locking.
In my case, the trigger was attempting to insert into table dbname.tablename. However, I misspelled it as wongdbname.tablename. The error message was that "Table 'tablename' is not locked".
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.