2010-01-06 64 views
2

考慮:MySQL數據庫。有時,數據庫模式更改和更新將推出(以sql腳本的形式)。爲了保證應用(沒有重複的更新,沒有更新丟失等)更新的正確順序我計劃部署以下解決方案:中止MySQL的腳本有條件

  • CREATE TABLE元(名字TEXT PRIMARY KEY,VAL TEXT);
  • INSERT INTO元VALUES( '版本', '0');

每個更新腳本執行其被順序地分配一個版本N。在執行更新之前,腳本會檢查meta.version是否與之前的腳本版本N-1相匹配。執行更新後,meta.version更新爲N.我不需要防止多個腳本並行運行。

的問題:如何檢查版本並中止腳本,如果它不匹配?我想到執行

CALL `raise error` 

會打破腳本,但如何有條件地執行它取決於meta.version?不允許存儲過程。有意義的錯誤信息是一個優點。 This不提供合適的解決方案。

回答

1

我認爲這最好在shell腳本或安裝程序應用程序中解決。你不能在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

當然,您可以修改原始腳本以不選擇任何行,這完全取決於您。

+0

是的,這是完美的包裝腳本,但然後我需要確保每個人都使用這個包裝腳本的更新。當然,這不會奏效。我需要「automagic」解決方案 - 無論是sql更新腳本還是不行。 – ygrek 2010-01-06 10:35:36

+0

怎麼樣然後http://stackoverflow.com/questions/773889/way-to-abort-execution-of-mysql-scripts-raising-error-orhaps/1275431#1275431 – 2010-01-06 10:51:28

+0

非常可怕:) 看起來像是有沒有「直接」的解決方案.. – ygrek 2010-01-11 10:43:42

1

好的,新答案。這與其說是賞金讓我更有創意,而我覺得少了剋制,提出一個解決方案的不直考慮:)

(我仍然假設你想避免存儲套路可言成本)

解決方案1:使用預處理語句

假設你uprades腳本是一個簡單的:

ALTER TABLE t ADD COLUMN c INT DEFAULT 1 

那麼如何AB出這樣的:

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:美國一個事先準備好的聲明殺

你已經指出,你不喜歡你太多鏈接的解決方案的連接......是因爲,或因爲存儲功能的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來解釋它:)

+0

現在我看到你第一次使用包裝腳本的答案是最簡單的麻煩。我會走這條路。謝謝。 – ygrek 2010-01-12 09:09:23

+0

謝謝ygrek。儘管功能不完善,但我希望您仍然可以完成您的工作。我也希望它更容易。 – 2010-01-12 09:29:55

+0

@RolandBouman,您的「Mysql Proxy」鏈接已關閉。順便說一下,使用MySQL「代理」並簡單地在應用程序中執行它,有什麼區別?通過Java或PHP? – Pacerier 2015-03-10 06:38:51