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之间没有空格
------------------------------------
由于数据库基础不是很好,还没找到好的方法实现调用存储过程返回数据集的操作,望各位赐教!
以后补充.
skynet 创建存储过程脚本的更多相关文章
- mysql命令行创建存储过程命令行定时执行sql语句
mysql -uroot -p show databases; use scm; show tables; show procedure status; 其他命令: SHOW VARIABLES LI ...
- SQLServer之创建存储过程
创建存储过程注意事项 在 SQL Server. Azure SQL Database.Azure SQL 数据仓库和并行数据库中创建 Transact-SQL 或公共语言运行时 (CLR) 存储过程 ...
- mysql创建存储过程,定时任务,定时删除log
-- 创建存储过程 清除30天前的日志create procedure deleteLog()BEGINdelete from contract_vlog where create_time<D ...
- mysql 创建存储过程报错
在创建存储过程前把结束符定义为 delimiter // 然后再创建就不会报错
- 《转》Unity3D研究院编辑器之创建Lua脚本模板
Unity里能创建 c#脚本模板,但是如果我想创建Lua脚本模板怎么办呢?拓展一下编辑器吧. 设置一下Lua脚本的模板地址 : Assets/Editor/Lua/Template/lua.lua ...
- 利用navicat创建存储过程、触发器和使用游标的简单实例
利用navicat创建存储过程.触发器和使用游标的简单实例 标签: navicat存储过程触发器mysql游标 2013-08-03 21:34 15516人阅读 评论(1) 收藏 举报 分类: 数 ...
- SQL Server 2008 存储过程,带事务的存储过程(创建存储过程,删除存储过程,修改存储过
SQL Server 2008 存储过程,带事务的存储过程(创建存储过程,删除存储过程,修改存储过 存储过程 创建存储过程 use pubs --pubs为数据库 go create proc ...
- mysql 创建存储过程注意
最近在利用navicat创建存储过程时,总是报1064语法错误,而且每次都是指向第一行,百思不得姐,如下图: 后来发现,原来是输入参数没有定义长度导致,所以以后真要注意 加上入参长度即可:IN `sT ...
- 关于如何使用Navicat(11.1.13) for MySQL如何创建存储过程
1.ƒ()函数(右键)→新建函数(左键)→过程(选择) 2.会遇到的问题 问题一:因为sql语句默认以;为结束符,所以应该修改结束符,但是这在Navicat(11.1.13) for MySQL中是不 ...
随机推荐
- 7.15;linux命令
麦克维瀑布 https://farm5.staticflickr.com/4269/34749113172_d6c1ba274a_k.jpg ----------------------------- ...
- 170111、MapperScannerConfigurer处理过程源码分析
前言 本文将分析mybatis与spring整合的MapperScannerConfigurer的底层原理,之前已经分析过java中实现动态,可以使用jdk自带api和cglib第三方库生成动态代理. ...
- Phonetic Symbols&Rules of Pronunciation
音标 Phonetic Symbols http://yinbiao.tingclass.net/ 1.1元音 1.1.元音:元音有20个,其中单元音12个,双元音8个. (1)“短”单元音 [i] ...
- Replay attack 回放攻击
w http://baike.baidu.com/item/重放攻击 重放攻击(Replay Attacks)又称重播攻击.回放攻击或新鲜性攻击(Freshness Attacks),是指攻击者发送一 ...
- Java基础 - 面向对象 - 类方法传参
调用方法时可以给该方法传递一个或多个值,传给方法的值叫实参,在方法内部,接收实参的变量叫做形参,形参的声明语法与变量的声明语法一样.形参只在方法内部有效. Java中方法的参数主要有3种,分别为值参数 ...
- java 日期的格式化 输入/输出
想要得到形如2018.07.09的格式化好的当天日期 创建Date对象,调用SimpleDateFormat对象的format方法: indexstr="logstash-"+ne ...
- 浅谈REDIS数据库的键值设计(转)
add by zhj: 关系数据库表的一条记录可以映射成Redis中的一个hash类型,其实数据库记录本来就是键值对.这样,要比本文中的键设计用更少的键,更节省内存,因为每个键除了它的键值占用内存外, ...
- 报错:PermissionError: [WinError 5] Access is denied: 'C:\\Program Files\\Anaconda3\\Lib\\site-packages\\pywebhdfs'
Outline 在本(Windows系统)地往 “PAI”(hdfs)上上传数据时,需要安装pywebhdfs包,然后就报错了: 报错信息: PermissionError: [WinError 5] ...
- JavaScript历史和标准
不管新手老手, 学门语言如果不简单了解这门语言谁创立的, 什么时候, 现在由谁来维护, 规范在哪? 总感觉, 少了点什么, 我就是这样. 历史 1994年美国网景(Netscape)公司发布自己的浏览 ...
- 使用githubs托管代码
此文章已经发表于本人博客. 最近在学习nodejs,使用它自己都蛮觉得有激情哦,相信自己路学下去.在学习的过程中nodejs很多插件都在github上,于是自己也用了这个东东感觉不错,开始的时候还用命 ...