Mysql - 游标/动态sql/事务
游标这个在我目前的项目里面用的还不多, 但是其功能还是很强大的.
动态sql以前都没用过, 是跟着富士康(不是张全蛋的富土康哦)过来的同事学的. 还是挺好用的. 我的数据库方面, 跟他学了不少. 在此, 感谢他一下, 建华锅锅.
事务在前面的篇章中其实已经出现过了, 这个东西好像还是程序中用的比较多一点.
由于之前的工作中碰到过一个场景, 正好将游标,动态sql,事务都用上了, 那么我也弄一个例子好了, 想了一个别的场景, 与工作的那个场景不相干, 并没有泄露公司业务机密之类的啊.
先看例子吧, 然后在后面, 我补上语法.
一、例子
1. 建表
既然是讲例子, 当然不能忘记建表嘛, 从0开始.
create table Goods
(
Id int not null PRIMARY key auto_increment,
Code varchar() comment '编码',
Name varchar() comment '名称',
Count int comment '数量',
Brand varchar() comment '品牌'
) default charset=utf8 comment '商品表'; create table GoodDetails
(
Id int not null PRIMARY key auto_increment,
GId int not null comment 'Goods表Id',
Name varchar() comment '名称',
Code varchar() comment '编码明细',
Remark varchar() comment '备注'
) default charset=utf8 comment '商品明细';
2. 加入基础数据

3. 虚拟场景介绍
公司最近进了一批物品, 就是上面的Goods表了, 并且准备给每一个物品进行编码(编码规则就是用Goods表的Code加上流水号, 去生成), 并打上条形码.
这里的功能就是生成商品明细和流水号的问题了, 一键生成. 这里通常的实现方式有两种:
方式一 : 程序生成
在程序中, 读取需要生成的数据, 比如上面这四条, 然后循环每一条, 给数据加上编码, 总共生成出12条数据, 在吧这12条数据, 存入明细表中. 在数据量少的时候还好, 完全可以接受, 但是如果数据量多了, 那速度, 慢的让人有砸电脑的冲动. Goods表的几条数据, 到GoodDetails表中, 会变成数百, 甚至上千, 上万.
方式二 : 数据库生成
如果不想读取出来再插入, 并且逻辑处理并不多,不复杂的情况下, 可以使用数据库去生成. 还是很方便的, 速度也提升非常多.
那这里, 我只介绍方式二了, 方式一, 只是处理麻烦一点.
4. 脚本:
delimiter $
drop PROCEDURE if EXISTS p_autocreate;
CREATE PROCEDURE `p_autocreate`(IN g_ids VARCHAR(1000), IN nolength INT)
BEGIN
DECLARE res_code INT; DECLARE res_msg VARCHAR (50); /*临时表的条数*/
DECLARE t_count INT; /**游标内使用变量**begin**/
DECLARE g_id INT; DECLARE g_code VARCHAR (50); DECLARE d_code VARCHAR (50); DECLARE g_count INT (11); DECLARE g_name VARCHAR (20);
/**游标内使用变量**end**/ /**游标的位置**/
DECLARE v_index INT DEFAULT 1; DECLARE done BIT DEFAULT 0; /*声明游标*/
DECLARE g_cursor CURSOR FOR SELECT id, CODE, NAME, COUNT FROM temp_goods; /*游标查询时, 如果找不到下一个了, 会将done置为1*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; /**创建临时表**begin**/
DROP TABLE IF EXISTS temp_goods;
CREATE TEMPORARY TABLE temp_goods (
Id INT NOT NULL, -- PRIMARY key auto_increment,
CODE VARCHAR (50),
NAME VARCHAR (20),
COUNT INT
) DEFAULT CHARSET = utf8;
/**创建临时表**end**/ /**初始化返回值**begin**/
SET res_code := "-99"; SET res_msg := "OK";
/**初始化返回值**end**/ IF (g_ids IS NOT NULL OR LENGTH(g_ids) > 0) THEN
SET @v_sql := CONCAT("INSERT INTO temp_goods(Id,Code,Name,Count) ",
" select Id,Code,Name,Count from Goods ",
" where ",
" find_in_set(id, ",
CHAR(34),
g_ids,
CHAR(34),
")>0 ;"); /*预编译此动态sql, 并存入stmt中*/
PREPARE stmt FROM @v_sql; /*执行此动态sql, 此动态sql的作用, 是从Goods中提取有效数据*/
EXECUTE stmt; /*释放此资源*/
DEALLOCATE PREPARE stmt; SELECT COUNT(1) INTO t_count FROM temp_goods; START TRANSACTION; -- 开始事务 IF (t_count > 0) THEN
/*打开游标*/
OPEN g_cursor; REPEAT
/*这里的顺序要与之前的顺序保持一致*/
FETCH g_cursor INTO g_id, g_code, g_name, g_count; IF NOT done THEN SET v_index := 1; IF (IFNULL(g_count, 0) > 0) THEN WHILE (v_index <= g_count)
DO
SET d_code := CONCAT(g_code, LPAD(v_index, nolength, "0")); INSERT INTO GoodDetails(GId, NAME, CODE) VALUES (g_id, g_name, d_code); SET v_index := v_index + 1;
END WHILE;
END IF;
END IF;
UNTIL done END REPEAT; -- 结束repeat循环
CLOSE g_cursor; /*关闭游标*/ COMMIT; -- 提交事务 ELSE ROLLBACK; -- 回滚事务 SET res_code := "10"; SET res_msg := "系统中不存在相关记录.";
END IF;
ELSE
SET res_code := "5"; SET res_msg := "请选择要生成的记录";
END IF; DROP TABLE IF EXISTS temp_goods; SELECT res_msg;
END $
delimiter ;
5. 结果:
执行这个存储过程
call p_autocreate('1,2,3,4', 3);

ok, 执行成功, 接下来, 来看一下GoodDetails表的数据:

我这里的例子, 已经是最简单的一个例子了, 在实际使用过程中, 可能比这个还要复杂一些, 数据更多一些.
不过说到这个数据量, 我倒不介意, 多做一个实验.
6. 实验
我将各自的数据量, 都修改为 10000, 如下图, 这个时候, 要生成 40000 条数据, 并且插入到表中去. 如果使用程序处理插入数据库的方式, 确实会慢一些.

数据库的方式, 确实会快很多. 如下图, 生成4w条数据, 然后插入GoodDetails表中, 花了不到4s的时间. 算是一个比较快的时间了.

OK, 接下来, 就来介绍一下他们的语法.
二、游标
1. 语法
1.1 声明游标
declare 游标名 cursor for select 列名 from 表
1.2 打开游标
open 游标名
1.3 游标前进
fetch 游标名 into 变量a, 变量b ...
1.4 关闭游标
close 游标名
2. 注
既然游标执行的方式, 像是一个循环, 那么什么时候才知道这个循环要结束呢.
例子里面, 有一句话, DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 这句话的意思, 其实就是当游标找不到下一条数据的时候, 就回将变量 done 修改为1.
三、动态sql
1. 语法
1.1 准备sql变量
此sql变量必须是字符串格式的哦. 这样可以动态生成需要执行的sql.
1.2 预编译
PREPARE stmt FROM @v_sql;
这里的stmt是一个变量, 名称自己取
1.3 执行
EXECUTE stmt;
1.4 释放资源
DEALLOCATE PREPARE stmt;
四、事务
1. 语法
到这里, 我突然不知道说些什么了. 那就简单介绍下吧
1.1 开始事务
start transation;
1.2 提交事务
commit;
1.3 回滚事务
rollback;
Mysql - 游标/动态sql/事务的更多相关文章
- MySQL存储过程动态SQL语句的生成
用Mysql存储过程来完成动态SQL语句,使用存储过程有很好的执行效率: 现在有要求如下:根据输入的年份.国家.节假日类型查询一个节假日,我们可以使用一般的SQL语句嵌入到Java代码中,但是执行效率 ...
- mysql 存储过程 动态sql例子
proc:BEGIN ; ; ; ) DEFAULT ''; ) DEFAULT ''; ) DEFAULT '';#插入日志的表,一个活动一张表 #将局部变量转换成会话变量 #动态sql语言只接受会 ...
- MySQL基础----动态SQL语句
尊重原创:http://blog.csdn.net/abc19900828/article/details/39501643 动态sql语句基本语法 1 :普通SQL语句可以用Exec执行 eg: ...
- mysql游标的用法及作用
1当前有三张表A.B.C其中A和B是一对多关系,B和C是一对多关系,现在需要将B中A表的主键存到C中:常规思路就是将B中查询出来然后通过一个update语句来更新C表就可以了,但是B表中有2000多条 ...
- MyBatis 的动态 SQL 使用说明
动态SQL简介 参考文档地址:http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 ...
- MySQL通过视图(或临时表)实现动态SQL(游标)
>参考de优秀文章 写MySQL存储过程实现动态执行SQL Dynamic cursor in stored procedure MySQL通过视图(或临时表)实现动态SQL(游标). 因在实现 ...
- 使用动态SQL处理table_name作为输入参数的存储过程(MySQL)
关于mysql如何创建和使用存储过程,参考笔记<MySQL存储过程和函数创建>以及官网:https://dev.mysql.com/doc/refman/5.7/en/create-pro ...
- MyBatis基础_连接池与事务、动态SQL、注解开发
一.MyBatis连接池及事务控制 1.连接池 在实际开发中,都会使用连接池,因为它可以减少获取连接缩消耗的时间.所谓连接池,就是存储数据库连接的容器.连接池中存储一定数量的数据库连接,当线程需要使用 ...
- 游标、动态sql、异常
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlIAAAFeCAIAAADBl2bCAAAgAElEQVR4nOyddXgU197H12OEELxIkV
随机推荐
- 创建 OVS flat network - 每天5分钟玩转 OpenStack(134)
上一节完成了 flat 的配置工作,今天创建 OVS flat network.Admin -> Networks,点击 "Create Network" 按钮. 显示创建页 ...
- 通过 floating IP 访问 VIP - 每天5分钟玩转 OpenStack(126)
前面我们是直接用 curl 测试 VIP,在更为真实的场景中通常会使用 floating IP 访问 VIP. 下面我们给 VIP 关联一个 floating IP,再进行测试. 访问 Project ...
- jQuery学习之路(3)- 事件
▓▓▓▓▓▓ 大致介绍 jQuery增加了并扩展了基本的事件处理机制,不但提供了更加优雅的事件处理语法,而且极大地增强了事件处理能力 ▓▓▓▓▓▓ jQuery中的事件 ▓▓▓▓▓▓ 加载DOM 在j ...
- RabbitMq应用一
RabbitMq应用一 RabbitMQ的具体概念,百度百科一下,我这里说一下我的理解,如果有少或者不对的地方,欢迎纠正和补充. 一个项目架构,小的时候,一般都是传统的单一网站系统,或者项目,三层架构 ...
- [EasyUI美化换肤]更换EasyUi图标
前言 本篇文章主要是记录一些换EasyUI皮肤的过程,备忘.也欢迎美工大神各路UI给点好意见,EasyUI我就不介绍了,自行百度吧..(So..所以别问我是不是响应式..本身EasyUI就不是响应式. ...
- 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型
前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...
- 【手记】注意BinaryWriter写string的小坑——会在string前加上长度前缀length-prefixed
之前以为BinaryWriter写string会严格按构造时指定的编码(不指定则是无BOM的UTF8)写入string的二进制,如下面的代码: //将字符串"a"写入流,再拿到流的 ...
- isEmpty和isNull()区别
isEmpty和isNull()区别一个NULL字符串一定是一个空串,一个空串未必是一个NULL字符串例如:QString().isNull(): //结果为trueQString().isEm ...
- Android之文件数据存储
一.文件保存数据介绍 Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的.文件可用来存放大量数据,如文本.图 ...
- Ubuntu(Linux) + mono + xsp4 + nginx +asp.net MVC3 部署
折腾了一下,尝试用Linux,部署mvc3. 分别用过 centos 和 ubuntu ,用ubuntu是比较容易部署的. 操作步骤如下: 一.终端分别如下操作 sudo su ->输入密码 a ...