skynet 創建存儲過程腳本

最近主程更改了數據庫的操作方案,由之前的拼寫sql腳本轉爲在mysql端創建好存儲過程後,直接調用存儲過程。

首先對一個表測試上述過程:

數據庫端存儲過程:(測試表)

CREATE TABLE `randomval` (
  `id` int(10) unsigned NOT NULL,
  `val` int(10) unsigned NOT NULL,
  `step` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

創建存儲過程:

DELIMITER $$

  CREATE DEFINER=`root`@`%` PROCEDURE `qy_insert_randomval`(IN in_id int, IN in_val int, IN in_step int)
  BEGIN 
    insert into randomval (`id`, `val`, `step`) values (in_id, in_val, in_step)
    on duplicate key update `id` = in_id, `val` = in_val, `step` = in_step;
  END $$

  DELIMITER;

skynet的連接:更改的test下的testmysql.lua

skynet.start(function()
    local function on_connect(db)
        db:query("set charset utf8");
    end
    local db=mysql.connect({
        host="127.0.0.1"或"局域網ip",
        port=3306,
        database="XXXX",
        user="XXXX",
        password="XXXX",
        max_packet_size = 1024 * 1024,
        on_connect = on_connect
    })    
           
    if not db then
        print("failed to connect")
    end 
    --拼接調用存儲過程的sql語句
    print("testmysql success to connect to mysql server")

  --表t的格式忽略,和項目有關,可自定義
    local t = {__fields = {id = 34, val = 30, step = 50}, __tname = "randomval", __head_ord = {"id", "val", "step"} }
    local tmp_sql = {}
        local sql_first_part = string.format("call " .. "qy_insert_" .. t.__tname .. "(" )
        table.insert(tmp_sql, sql_first_part)
           
        assert(nil ~= t.__head_ord)
        local counter = 0
        for k, v in ipairs(t.__head_ord) do
            print(k, v)  
            assert(nil ~= t.__fields[v])
            if counter > 0 then
                table.insert(tmp_sql, ", ")
            else
                counter = counter + 1
            end
                
            if type(t.__fields[v]) == "string" then
                table.insert(tmp_sql, string.format("'%s'",t.__fields[v] ))
            else
                table.insert(tmp_sql, string.format("%s", t.__fields[v]))
            end
        end

        table.insert(tmp_sql, ")")    
        print("sql is :", table.concat(tmp_sql))
        db:query(table.concat(tmp_sql))


    --db:disconnect()
    --skynet.exit()                     
end)                

這時表,存儲過程都創建好了,運行testmysql腳本: ./skynet ./examples/config.mysql

成功調用存儲過程並插入一條記錄. 

由於主程要求每個表都要有一個“插入不成功就更新的存儲過程”,雖說用了navicat,但是目前對它的瞭解,只能一個一個的創建,很麻煩;

要不就是執行一個創建所有過程的sql腳本,用navicat執行創建。於是選擇了後者。

首先提取共性,需要以下:

(1) 統一命名爲"qy_insert_" + "表名"的格式 

(2) 獲取需要創建存儲過程的表名,表的每個字段名,字段類型(TABLE_TYPE)和 字段的值類型 (DATA_TYPE)

以下是實現:

  local addr = io.open("./user_sqlscript.sql", "w")
    assert(addr)
    local sql = "select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = " .. '"' .. "數據庫名稱" .. '"' //到這裏選出的是數據庫中所有的表。加上後面是篩選需要的表 .. "and TABLE_NAME NOT like" .. "'" .. "g_%" .. "'";
   

  print(sql)
    local table_list = db:query(sql)
--[[

  DELIMITER $$

  CREATE DEFINER=`root`@`%` PROCEDURE `qy_insert_randomval`(IN in_id int, IN in_val int, IN in_step int)
  BEGIN 
    insert into randomval (`id`, `val`, `step`) values (in_id, in_val, in_step)
    on duplicate key update `id` = in_id, `val` = in_val, `step` = in_step;
  END $$

  DELIMITER;

  以此存儲過程爲例

--]]
    for k, v in ipairs(table_list) do
        local script =  {}
        local tmpsql1 = {} -- 存儲 `qy_insert_randomval`(IN in_id int, IN in_val int, IN in_step int)中的 “IN in_id int, IN in_val int, IN in_step int”
        local tmpsql2 = {} --存儲 insert into randomval (`id`, `val`, `step`) 中的 “`id`, `val`, `step`”
        local tmpsql3 = {} --存儲 values (in_id, in_val, in_step) 中的 “in_id, in_val, in_step”
        local tmpsql4 = {} --存儲 on duplicate key update `id` = in_id, `val` = in_val, `step` = in_step; 中的  “`id` = in_id, `val` = in_val, `step` = in_step”

        local sql = string.format("select COLUMN_NAME , DATA_TYPE , COLUMN_TYPE from information_schema.`COLUMNS` where table_name = " .. '"' .. "%s" .. '";', v.TABLE_NAME)

    --COLUMN_NAME 是列名, COLUMN_TYPE 是列的類型如(varchar,int(6)unsigned)等,DATA_TYPE是該列的值類型(int, varchar)等
        print(sql)                     
        local col_val = db:query(sql)  
        assert(col_val)                 
        for k, v in ipairs(col_val) do 
            for sk, sv in pairs(v) do  
                if sv == "int" then 
                    print("string is ")
                end                      
            end                        
        end                            
                        
        --format each percudure part   
        local idx = 0                       
        for sk, sv in ipairs(col_val) do
            if sv.DATA_TYPE == "varchar" then
                table.insert(tmpsql1, string.format("IN %s %s", "in_" .. sv.COLUMN_NAME, sv.COLUMN_TYPE))
            else
                table.insert(tmpsql1, string.format("IN %s %s", "in_" .. sv.COLUMN_NAME, sv.DATA_TYPE))
            end

            table.insert(tmpsql2, string.format("`%s`", sv.COLUMN_NAME))
            table.insert(tmpsql3, string.format("in_%s", sv.COLUMN_NAME))
            table.insert(tmpsql4, string.format("`%s` = in_%s", sv.COLUMN_NAME, sv.COLUMN_NAME))
        end 


        --chain all tmpsqlx up
        table.insert(script, "DELIMITER $$\n")
        table.insert(script, string.format("CREATE DEFINER=`root`@`%%` PROCEDURE `%s`(", "qy_insert_" .. v.TABLE_NAME))
        table.insert(script, table.concat(tmpsql1, “,”)  .. ")\n")
        table.insert(script, "BEGIN \n")
        table.insert(script, string.format("insert into %s (%s values (%s)", v.TABLE_NAME, table.concat(tmpsql2, ","), table.concat(tmpsql3, ",") .. ")\n"))
        table.insert(script, string.format("on duplicate key update %s ;\n", table.concat(tmpsql4, ",")))
        table.insert(script, "END$$ \n")
        table.insert(script, "DELIMITER ;")
        local percudure = table.concat(script)
        print(percudure)

        addr:write(percudure)
        addr:write("\n\n")
    end 
    addr:close() --打開文件別忘了關閉

以上代碼實現了一個從數據庫中查詢出所有的表及其列名,列的類型,然後拼裝成每個表需要的存儲過程。

前面說到用到的工具是navicate當用工具創建存儲過程時:function->procedure->輸入參數-> 直接在BEGIN,END中間寫過程。

而且用此方法創建時,得到的存儲過程代碼是沒有下面的內容的

DELIMITER

...

...

END $$

DELIMITER;

因此,一開始沒有意識到此問題,我直接將生成的sql文件用navicate生成存儲過程時是有問題的,總是說存儲過程有問題,但是對比用navicat直接生成的代碼,又是一模一樣的。因此很鬱悶。

網上搜資料找到要加上上面的內容,然後生成成功.

原因在這篇文章中敘述的挺詳細的:

http://blog.sina.com.cn/s/blog_4c197d420101d3oa.html

------------------------------分割線------------------------------

skynet中庸存儲過程查詢數據庫並接受返回值時可以這樣使用:

db:query(“call 存儲過程名(@a,@b, @c)”)

local r = db:query("SELECT @a, @b, @c")

注:傳出變量爲@a,@b,@c ,切@a之間沒有空格

------------------------------------

由於數據庫基礎不是很好,還沒找到好的方法實現調用存儲過程返回數據集的操作,望各位賜教!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章