2

与えられた:MySQLデータベース。dbスキーマの変更と更新が(SQLスクリプトの形式で)ロールアウトされる場合があります。適用される更新の正しい順序(重複する更新がない、更新が欠落していないなど)を保証するために、次のソリューションを展開する予定です。

  • CREATE TABLE meta(name TEXT PRIMARY KEY、val TEXT);
  • INSERT INTO meta VALUES('version'、 '0');

各更新スクリプトには、順番に割り当てられるバージョンNが含まれています。更新を実行する前に、スクリプトはmeta.versionが以前のスクリプトバージョンN-1と一致することを確認します。更新を実行した後、meta.versionはNに更新されます。並行して実行される複数のスクリプトから保護する必要はありません。

質問:バージョンを確認し、一致しない場合はスクリプトを中止するにはどうすればよいですか?私はそれを実行することを理解しました

CALL `raise error`

スクリプトは壊れますが、meta.versionに応じて条件付きで実行するにはどうすればよいですか?ストアドプロシージャは許可されていません。意味のあるエラーメッセージはプラスです。これは適切な解決策を提供しません。

4

2 に答える 2

1

これは、シェルスクリプトまたはインストーラーアプリで解決するのが最善だと思います。SQLスクリプトに実際に制御構造を含めることはできません。

非常に簡単な解決策は、メタテーブルの選択に基づいて実行する実際のスクリプトのコマンドラインを生成するスクリプトを作成することです。

それで、あなたがこのスクリプトを持っているとしましょう、gen_upgrade_command.sql

select concat(
       'mysql -u<user> -p<password> -h<host> -e"SOURCE upgrade'
   ,    val + 1
   ,   '.sql"'
   )
from meta;

あなたはこのように実行します

mysql -u<user> -p<password> -h<host> -Nrs < gen_upgrade_command.sql > do_upgrade.bat

ここで、do_upgrade.batこの生成されたコマンドラインが含まれています。

mysql -u<usere> -p<password> -h<host> -e"SOURCE upgrade1.sql"

実行do_upgrade.batすると実行されますupgrade1.sql

もちろん、元のスクリプトを変更して、行をまったく選択しないようにすることもできます。それはあなた次第です。

于 2010-01-06T10:15:02.413 に答える
1

わかりました、新しい回答。賞金が私をより創造的にするほどではありません、むしろ私は私がまっすぐに考えていない解決策を提案するための制約をあまり感じません:)

(私はまだあなたが保存されたルーチンを絶対に避けたいと思っていると思います)

解決策#1:プリペアドステートメントを使用する

upradesスクリプトが単純であると仮定します。

ALTER TABLE t ADD COLUMN c INT DEFAULT 1

では、これはどうですか。

SET @version := '1';

SELECT CASE val
           WHEN @version THEN 
               'ALTER TABLE t ADD COLUMN c INT DEFAULT 1'
           ELSE 'SELECT ''Wrong version. Nothing to upgrade.'''
       END
INTO   @stmt
FROM   meta 
WHERE  name = 'Version';

PREPARE stmt FROM @stmt;
EXECUTE stmt;

明らかな欠点:

  • 個々のステートメントごとにこれを記述する必要があるため、混乱とオーバーヘッドを解消します(PREPARE複数のステートメントをバッチ処理することはできません)
  • アップグレードスクリプトの各ステートメントを文字列として記述しなければならないため、さらに煩わしい...
  • すべてのステートメントをで記述および実行できるわけではありませんPREPARE

解決策#2:接続を強制終了するための1つのプリペアドステートメント

リンクしたソリューションも嫌いなことをすでに指摘しました...それはKILLステートメントのせいですか、それともストアド関数のせいですか?ストアド関数が原因である場合は、次のことを回避できます。

SET @version := '1';

SELECT CASE val 
           WHEN @version THEN 'SELECT ''Performing upgrade...'''
           ELSE CONCAT('KILL CONNECTION', connection_id())
       END
INTO   @stmt
FROM   meta
WHERE  name = 'Version';

PREPARE stmt FROM @stmt;
EXECUTE stmt;  -- connection is killed if the version is not correct.

-- remainder of the upgrade script goes here...
  • mysql--skip-reconnect接続が切断された場合にステートメントを実行できないようにするオプションを指定して開始する必要があります

私はこの欠点を回避しPREPARE、ユーザーの削除や特権の取り消しなど、現在の接続をブロックする他の目的に使用しようとしました。残念ながら、それは意図したとおりには機能しません(いいえ、後も機能しませんFLUSH PRIVILEGES

解決策3:mysqlプロキシを使用して傍受する

さらに別の解決策:プロキシを使用します。mysqlプロキシ(http://forge.mysql.com/wiki/MySQL_Proxyを参照)を使用すると、カスタムコマンドを解釈するカスタムインターセプトスクリプトをluaで記述できます。これを使用して、必要な制御構造を追加できます。欠点:独自のミニ言語を設計し、それを解釈するためにluaを学ぶ必要があります:)

于 2010-01-11T12:06:07.370 に答える