【MySQLでLOCKとBEGIN】


Apache2.xとPHP4.3.xとMySQL4.1.xを使用しています。

InnoDBで作成したテーブルがあります。

あるデータをselectして
その結果によってupdateをかけ、
その後、また、selectし、
その結果によって、全体の処理を巻き戻したりしたいと考えています。

さて、このとき、別ユーザーから同時に接続されると結果がおかしくなるので、
LOCK TABLES・・・を使います。

あとで、巻き戻す(ROLLBACK)ために、
最初にBEGINしたいのですが、
LOCK TABLESの後にBEGINすると、テーブルのロックが解除されてしまいます。

LOCK TABLESとBEGIN~ROLLBACKを併用することは不可能なのでしょうか?

また、不可能な場合、別の方法などがあれば教えてください。

回答の条件
  • 1人10回まで
  • 登録:
  • 終了:2007/05/04 17:00:12
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答0件)

回答はまだありません

  • id:kurukuru-neko

    LOCK TABLESは以下の制限があります。
    以下の注記なのでトランザクション中
    では使うと副作用があるのでlock tables
    とトランzクション制御は同時に使う事は
    出来ません。

    注意: LOCK TABLES はトランザクションセーフではありません。アクティブなトランザクションは、テーブルロックの試行前に暗黙的にコミットされます。

    http://dev.mysql.com/doc/refman/4.1/ja/lock-tables.html
    http://dev.mysql.com/doc/refman/4.1/en/lock-tables.html

    排他するだけなら。
    begin
    select xxxx for update;
    update xxx;
    select xxx for update;
    update xxxx;

    rollback or commit;

    但し参照SQLは
    select xxx lock in shared mode;
    を全て記述する必要がある。

    LOCK TABLESを使う場合は、

    set AUTOCOMMIT = 0
    begin
    lock tables xxx write
    select xxx

    commit or rollback
    unlock tables

    参照側
    http://dev.mysql.com/doc/refman/4.1/en/innodb-and-autocommit.html

    set AUTOCOMMIT = 0
    select xxxx

  • id:caster777
    コメント欄にありがとうございます。

    > 排他するだけなら。
    > begin
    > select xxxx for update;
    > update xxx;
    > (※1)
    > select xxx for update;
    > update xxxx;
    >
    > rollback or commit;

    このとき、※1のタイミングで別ユーザーが同じ処理をした場合、整合性があわなくなる可能性がありますよね。

    -*--*--*--*--*--*--*--*--*--*--*--*--*-

    > LOCK TABLESを使う場合は、

    > set AUTOCOMMIT = 0
    > begin
    > lock tables xxx write
    > select xxx
    > (※2)
    > commit or rollback
    > unlock tables

    この場合、※2でupdate or insertしたとき、rollbackしても戻らないんですよね。

    -*--*--*--*--*--*--*--*--*--*--*--*--*-

    リンクを確認したところ、やはり、LOCKとROLLBACKは同時には機能できないようですね。
  • id:kurukuru-neko
    >このとき、※1のタイミング

    InnoDBであればfor updateするとロック
    されて通常同時には実行できません。

    InnoDB以外では、begin/commit/rollback
    等はトランザクション機能しません。
    (99999は最大待ち時間)
    SELECT GET_LOCK("TABLE",99999);
    begin
    ・・・
    commit or rollback
    select RELEASE_LOCK("TABLE");

    >※2でupdate or insertしたとき、
    >rollbackしても戻らないんですよね

    それはおかしい。
    4.1.22で試してみましたが正しく処理されます。

    ※1、※2ともに動作がおかしいテーブルが
    InnoDBであればfor updateするとロック
    される。

    テーブルがInnoDBではないと思われます。

    show create table xxx;
    確認するか

    alter table xxx engine=innodb;
    としてInnoDBに変換する。


    http://dev.mysql.com/doc/refman/4.1/ja/innodb-transaction-isolation.html
  • id:caster777
    すみません。
    いろいろ実験している間に、InnoDBからMyISAMに変更したことを忘れてしまっていました。

    InnoDBで試したところ、正常に動作しました。
    申し訳ございません、お騒がせいたしました。

    ありがとうございました。

    200ポイント送付しておきましたので、ご確認ください。
  • id:kurukuru-neko

    厳密には以下の問題があります。
    (MYSQLも同様の考え)

    リードコミッティド隔離レベル
    http://www.postgresql.jp/document/pg823doc/html/transaction-iso.html
  • id:kurukuru-neko

    テーブルロックしたくない場合
    ロック用のテーブルを別に作り
    create table locktable(
    id int , primary key(id),
    lock datetime,
    ref int default 0
    )
    insert into locktable(1,now(),0);
    insert into locktable(2,now(),0);
    insert into locktable(3,now(),0);
    insert into locktable(4,now(),0);

    最初にロックテーブルの特定カラムを
    強制的にロック。

    begin
    update locktable set lock=now(),ref=ref+1 where id=1

    ...

    commit or rollback

    する方法があります。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません