MYSQL如何對數據進行自動化升級--以若是某數據表存在而且某字段不存在時則執行更新操做爲例

咱們在進行新的功能開發時,因爲歷史項目的存在,須要在程序起動時對數據進行判斷,若是發現是歷史版本的數據,則須要對數據進行一些特定的處理;若是是最新的數據,則跳過處理過程。這在系統的版本迭代中尤其重要!本文將闡述如何自動化的實現該過程。php

何爲自動化

  1. 每次系統啓動,均執行一次咱們設定好的SQL語句。
  2. 當數據表存在且未升級時,進行數據表的升級操做。
  3. 當數據表不存在或數據已經升過級時,不對數據表進行操做。

功能描述

在數據庫measurement中,當存在數據表web_app_menu,且該表中不存在db_type字段時,爲其添加db_type字段。同時,進行部分數據的更新及刪除操做。html

知識點

普通的MYSQL語句並不支持IF ELSE控制流

因此沒法使用普通的SQL語句來實現以下的僞代碼:mysql

if (存在('web_app_menu'))
    if (存在('db_type'))
       // 執行語句

解決方法:使用存儲過程來實如今MYSQL中的邏輯判斷,進行實現僞代碼中的邏輯功能。web

遇到;則會當即執行;前面的語句。

存儲過程在使用前,須要先進行定義,在定義的過程當中,咱們須要加入SQL語句,這就避免不了,咱們在SQL語句中出現;。而一旦;出現,mysql會當即執行;之前語句,此時,因爲咱們的存儲過程未定義完畢,因此會獲得一個「語法錯誤」的提示。spring

解決方法: 在定義存儲過程前,重寫;。以使得在定義存儲時,即便出現了;,也不被mysql執行。在定義結束後,再將重寫的;復原。sql

存儲定義後並不會自動執行

開始使用存儲時,可能會遇到一個誤區:儲存定義後,爲何沒有自動執行。其實MYSQL中的存儲過程,就像咱們在普通的語言中定義一個函數是同樣的道理。函數定義後,並不會自動執行,只有當函數被調用時,纔會被自動執行。因此,解決的方法也很簡單:調用存儲過程。數據庫

示例代碼

-- 將 ; 轉義爲 // (即遇到//才至關於;) 防止定義 存儲過程 時中,遇到 ; 而中斷的問題。
DELIMITER //
-- 若是存在存儲過程(sql函數)FUN20180516則將其刪除
DROP PROCEDURE IF EXISTS `FUN20180516` //
-- 新建存儲過程(sql函數),起名爲:FUN20180518。至關於C中的(void FUN20180516())
CREATE PROCEDURE `FUN20180516` ()
-- 定義函數開始(至關於C中的 { )
BEGIN
--     聲明變量 int hasDb
    DECLARE hasDb INT;
    DECLARE hasDbType INT;
--     執行語句(查詢數據表是否存在),並將返回值給hasDb
   SELECT count(*) INTO hasDb FROM information_schema.tables WHERE (table_schema = 'measurement') AND (table_name= 'web_app_menu');
--     若是數據表存在(注意:用=來判斷,而不是==)
    IF hasDb = 1 THEN
--         判斷字段是否存在
        SELECT count(*) INTO hasDbType FROM information_schema.columns WHERE (table_schema = 'measurement') and (table_name= 'web_app_menu') and (column_name = 'db_type');
--         字段不存在,則執行如下代碼    
        IF hasDbType = 0 THEN
            ALTER TABLE `web_app_menu` ADD `db_type` VARCHAR(31) NOT NULL;
            UPDATE `web_app_menu` SET `db_type` = 'web_app_menu' WHERE db_type = '';
            DELETE wr.* FROM web_app_menu_role wr WHERE wr.web_app_menu_id IN (SELECT w.id FROM web_app_menu w WHERE w.id IN (select w1.p_id FROM web_app_menu w1 WHERE w.route_name = 'measurementStandardAssessmentApply'));
            DELETE wr.* FROM web_app_menu_role wr WHERE wr.web_app_menu_id IN (SELECT w.id FROM web_app_menu w WHERE w.route_name = 'measurementStandardAssessmentApply');
            DELETE w.* FROM web_app_menu w WHERE w.p_id IN (SELECT id FROM (SELECT id FROM web_app_menu w2 WHERE w2.route_name = 'measurementStandardAssessmentApply') x);
            DELETE w.* FROM web_app_menu w WHERE w.route_name = 'measurementStandardAssessmentApply';
--             控制檯打印日誌
            SELECT '20180516 success';
        end if;
    END IF;
-- 下面咱們用 // 至關於 END ;也就是說,咱們的函數定義完了,你能夠一併進行加載了。
END //
-- 再將 ; 恢復爲 ;。防止後面的語句中,使用; 而不生效的問題
DELIMITER ;
-- 調用函數
call FUN20180516();

結合spring

首先: spring支持兩種方式在啓動時執行SQL語句。其中是在resources中創建data.sql,另外一種是創建schema.sql。兩個文件的區別在於:data.sql後於JPA執行,而schema.sql先於JPA執行。
因爲咱們須要在JPA起做用前先改變數據表的結構,刪除冗餘數據,因此須要創建schema.sqlapp

其次:spring並不支持DELIMITER語法,因此在schema.sql中,刪除DELIMITER //DELIMITER;。但一樣的,若是不重寫;,則還會出現遇到;則執行的問題。因此咱們還須要在配置文件中加入:spring.datasource.separator=//來起到重寫;的做用。函數

此時,schema.sql的形式以下:注意幾處//spring-boot

-- spring.datasource.separator=//已通過;進行了改寫
-- 若是存在存儲過程(sql函數)FUN20180516則將其刪除
DROP PROCEDURE IF EXISTS `FUN20180516` //
-- 新建存儲過程(sql函數),起名爲:FUN20180518。至關於C中的(void FUN20180516())
CREATE PROCEDURE `FUN20180516` ()
    -- 定義函數開始(至關於C中的 { )
    BEGIN
        --  聲明變量 int hasDb
        DECLARE hasDb INT;
        DECLARE hasDbType INT;
        --  執行語句(查詢數據表是否存在),並將返回值給hasDb
        SELECT count(*) INTO hasDb FROM information_schema.tables WHERE (table_schema = 'measurement') and (table_schema = 'measurement') AND (table_name= 'web_app_menu');
        --  若是數據表存在(注意:用=來判斷,而不是==)
        IF hasDb = 1 THEN
            --      判斷字段是否存在
            SELECT count(*) INTO hasDbType FROM information_schema.columns WHERE (table_name= 'web_app_menu') and (column_name = 'db_type');
            --      字段不存在,則執行如下代碼
            IF hasDbType = 0 THEN
                ALTER TABLE `web_app_menu` ADD `db_type` VARCHAR(31) NOT NULL;
                UPDATE `web_app_menu` SET `db_type` = 'web_app_menu' WHERE db_type = '';
                DELETE wr.* FROM web_app_menu_role wr WHERE wr.web_app_menu_id IN (SELECT w.id FROM web_app_menu w WHERE w.id IN (select w1.p_id FROM web_app_menu w1 WHERE w.route_name = 'measurementStandardAssessmentApply'));
                DELETE wr.* FROM web_app_menu_role wr WHERE wr.web_app_menu_id IN (SELECT w.id FROM web_app_menu w WHERE w.route_name = 'measurementStandardAssessmentApply');
                DELETE w.* FROM web_app_menu w WHERE w.p_id IN (SELECT id FROM (SELECT id FROM web_app_menu w2 WHERE w2.route_name = 'measurementStandardAssessmentApply') x);
                DELETE w.* FROM web_app_menu w WHERE w.route_name = 'measurementStandardAssessmentApply';
                --          控制檯打印日誌
                SELECT '20180516 success';
            end if;
        END IF;
    END //
-- 調用函數
call FUN20180516() //

application.properties

spring.datasource.separator=//

參考

http://www.cnblogs.com/geaozh...
http://blog.sina.com.cn/s/blo...
https://www.techonthenet.com/...
https://dba.stackexchange.com...
https://docs.spring.io/spring...
https://stackoverflow.com/que...
相關文章
相關標籤/搜索