LOCK TABLE文により明示的に、表に共有あるいは排他のロックをかけることができます。
表へのロックは現在のトランザクションが終了するまでの間、続きます。
表をロックできるのは、データベースの所有者と表の所有者です。
明示的な表へのロックは次の場合に便利です。
- 表の複数行へのロックによるオーバーヘッドを避ける時。(言い換えればユーザ自ら、ロックエスカレーションを行う時。)
- デッドロックを避ける時
この文でシステム表にロックをかけることはできません。
構文 LOCK TABLE 表名 IN { SHARE | EXCLUSIVE } MODE
いずれのモードであっても、トランザクションは表をロックした後、それ以上の行ごとのロックを得ることはできません。例えば、情報を読むためにトランザクションがFlightsという表の全体を共有モードでロックした後、ある文にて行を更新するために特定の行への排他ロックを必要としたとします。しかしながら、既にFlights表へのロックがあるため、排他ロックも表毎となる必要があります。
他の接続が表に対して既にロックをかけているため、その表へのロックが取得できない場合、デッドロックのタイムアウト時間が経過した後、文への例外が発生します。(SQLState X0X02)
例
行毎のロックが多量に発生することを避けるため、共有モードでFlightsという表全体へのロックを行うには以下の文を使います。
LOCK TABLE Flights IN SHARE MODE;
SELECT *
FROM Flights
WHERE orig_airport > 'OOO';
複数のUPDATE文を発行するトランザクションが一つあるとします。
個々の文はわずかな行毎のロックしか必要としないので、トランザクションはロックを表毎に変更しません。しかしUPDATE文の数が多いので、取得と開放が行われるロックの延べ数は多くなり、デッドロックになりかねません。
このようなトランザクションでは、最初に排他モードで表をロックします。
例を以下に示します。LOCK TABLE FlightAvailability IN EXCLUSIVE MODE;
UPDATE FlightAvailability
SET economy_seats_taken = (economy_seats_taken + 2)
WHERE flight_id = 'AA1265' AND flight_date = DATE('2004-03-31');
UPDATE FlightAvailability
SET economy_seats_taken = (economy_seats_taken + 2)
WHERE flight_id = 'AA1265' AND flight_date = DATE('2004-04-11');
UPDATE FlightAvailability
SET economy_seats_taken = (economy_seats_taken + 2)
WHERE flight_id = 'AA1265' AND flight_date = DATE('2004-04-12');
UPDATE FlightAvailability
SET economy_seats_taken = (economy_seats_taken + 2)
WHERE flight_id = 'AA1265' AND flight_date = DATE('2004-04-15');
トランザクションが表を更新する前に、その表をみる必要がある場合、デッドロックを避けるため、表に排他ロックをかけます。
例:LOCK TABLE Maps IN EXCLUSIVE MODE;
SELECT MAX(map_id) + 1 FROM Maps;
-- INSERT INTO Maps . . .