2021年9月

例子:

当前有三张表A、B、C其中A和B是一对多关系,B和C是一对多关系,现在需要将B中A表的主键存到C中;
常规思路就是将B中查询出来然后通过一个update语句来更新C表就可以了,但是B表中有2000多条数据,
难道要执行2000多次?显然是不现实的;最终找到写一个存储过程然后通过循环来更新C表,
然而存储过程中的写法用的就是游标的形式。

【简介】

    游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。

    游标充当指针的作用。

    尽管游标能遍历结果中的所有行,但他一次只指向一行。

    游标的作用就是用于对查询数据库所返回的记录进行遍历,以便进行相应的操作。

【用法】

    一、声明一个游标: declare 游标名称 CURSOR for table;(这里的table可以是你查询出来的任意集合)
    二、打开定义的游标:open 游标名称;
    三、获得下一行数据:FETCH  游标名称 into testrangeid,versionid;
    四、需要执行的语句(增删改查):这里视具体情况而定
    五、释放游标:CLOSE 游标名称;
  注:mysql存储过程每一句后面必须用;结尾,使用的临时字段需要在定义游标之前进行声明。

【实例】

复制代码

-  BEGIN  
  --定义变量  declare testrangeid BIGINT;  
declare versionid BIGINT;   
declare done int;  
--创建游标,并存储数据  declare cur_test CURSOR for   
   select id as testrangeid,version_id as versionid from tp_testrange;  
--游标中的内容执行完后将done设置为1  
 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;   
--打开游标  open cur_test;  
--执行循环    posLoop:LOOP  
--判断是否结束循环  
        IF done=1 THEN    
      LEAVE posLoop;  
    END IF;   
--取游标中的值  
    FETCH  cur_test into testrangeid,versionid;  
--执行更新操作  
    update tp_data_execute set version_id=versionid where testrange_id = testrangeid;  
  END LOOP posLoop;  
--释放游标  CLOSE cur_test;  
  
END  -

复制代码

例子2:

我们现在要用存储过程做一个功能,统计iphone的总库存是多少,并把总数输出到控制台。

复制代码

--在windows系统中写存储过程时,如果需要使用declare声明变量,需要添加这个关键字,否则会报错。  delimiter //  drop procedure if exists StatisticStore;  
CREATE PROCEDURE StatisticStore()  
BEGIN  
    --创建接收游标数据的变量  
    declare c int;  
    declare n varchar(20);  
    --创建总数变量  
    declare total int default 0;  
    --创建结束标志变量  
    declare done int default false;  
    --创建游标  
    declare cur cursor for select name,count from store where name = 'iphone';  
    --指定游标循环结束时的返回值  
    declare continue HANDLER for not found set done = true;  
    --设置初始值  
    set total = 0;  
    --打开游标  
    open cur;  
    --开始循环游标里的数据      read_loop:loop  
    --根据游标当前指向的一条数据  
    fetch cur into n,c;  
    --判断游标的循环是否结束  
    if done then  
        leave read_loop;    --跳出游标循环  
    end if;  
    --获取一条数据时,将count值进行累加操作,这里可以做任意你想做的操作,  
    set total = total + c;  
    --结束游标循环  
    end loop;  
    --关闭游标  
    close cur;  
  
    --输出结果  
    select total;  
END;  
--调用存储过程  call StatisticStore();

复制代码

fetch是获取游标当前指向的数据行,并将指针指向下一行,当游标已经指向最后一行时继续执行会造成游标溢出。
使用loop循环游标时,他本身是不会监控是否到最后一条数据了,像下面代码这种写法,就会造成死循环;

read_loop:loop  
fetch cur into n,c;  
set total = total+c;  
end loop;

在MySql中,造成游标溢出时会引发mysql预定义的NOT FOUND错误,所以在上面使用下面的代码指定了当引发not found错误时定义一个continue 的事件,指定这个事件发生时修改done变量的值。

declare continue HANDLER for not found set done = true;

所以在循环时加上了下面这句代码:

--判断游标的循环是否结束  if done then  
    leave read_loop;    --跳出游标循环  end if;

如果done的值是true,就结束循环。继续执行下面的代码

使用方式

游标有三种使用方式:
第一种就是上面的实现,使用loop循环;
第二种方式如下,使用while循环:

复制代码

drop procedure if exists StatisticStore1;  
CREATE PROCEDURE StatisticStore1()  
BEGIN  
    declare c int;  
    declare n varchar(20);  
    declare total int default 0;  
    declare done int default false;  
    declare cur cursor for select name,count from store where name = 'iphone';  
    declare continue HANDLER for not found set done = true;  
    set total = 0;  
    open cur;  
    fetch cur into n,c;  
    while(not done) do  
        set total = total + c;  
        fetch cur into n,c;  
    end while;  
      
    close cur;  
    select total;  
END;  
  
call StatisticStore1();

复制代码

第三种方式是使用repeat执行:

复制代码

drop procedure if exists StatisticStore2;  
CREATE PROCEDURE StatisticStore2()  
BEGIN  
    declare c int;  
    declare n varchar(20);  
    declare total int default 0;  
    declare done int default false;  
    declare cur cursor for select name,count from store where name = 'iphone';  
    declare continue HANDLER for not found set done = true;  
    set total = 0;  
    open cur;  
    repeat  
    fetch cur into n,c;  
    if not done then  
        set total = total + c;  
    end if;  
    until done end repeat;  
    close cur;  
    select total;  
END;  
  
call StatisticStore2();

复制代码

游标嵌套

在mysql中,每个begin end 块都是一个独立的scope区域,由于MySql中同一个error的事件只能定义一次,如果多定义的话在编译时会提示Duplicate handler declared in the same block。

复制代码

drop procedure if exists StatisticStore3;  
CREATE PROCEDURE StatisticStore3()  
BEGIN  
    declare _n varchar(20);  
    declare done int default false;  
    declare cur cursor for select name from store group by name;  
    declare continue HANDLER for not found set done = true;  
    open cur;  
    read_loop:loop  
    fetch cur into _n;  
    if done then  
        leave read_loop;  
    end if;  
    begin  
        declare c int;  
        declare n varchar(20);  
        declare total int default 0;  
        declare done int default false;  
        declare cur cursor for select name,count from store where name = 'iphone';  
        declare continue HANDLER for not found set done = true;  
        set total = 0;  
        open cur;  
        iphone_loop:loop  
        fetch cur into n,c;  
        if done then  
            leave iphone_loop;  
        end if;  
        set total = total + c;  
        end loop;  
        close cur;  
        select _n,n,total;  
    end;  
    begin  
            declare c int;  
            declare n varchar(20);  
            declare total int default 0;  
            declare done int default false;  
            declare cur cursor for select name,count from store where name = 'android';  
            declare continue HANDLER for not found set done = true;  
            set total = 0;  
            open cur;  
            android_loop:loop  
            fetch cur into n,c;  
            if done then  
                leave android_loop;  
            end if;  
            set total = total + c;  
            end loop;  
            close cur;  
        select _n,n,total;  
    end;  
    begin  
      
    end;  
    end loop;  
    close cur;  
END;  
  
call StatisticStore3();

复制代码

上面就是实现一个嵌套循环,当然这个例子比较牵强。凑合看看就行。

动态SQL

Mysql 支持动态SQL的功能

set @sqlStr='select * from table where condition1 = ?';  
prepare s1 for @sqlStr;  
--如果有多个参数用逗号分隔  execute s1 using @condition1;  
--手工释放,或者是 connection 关闭时, server 自动回收  deallocate prepare s1;


关于vue的npm run dev和npm run build

├─build
│   ├─build.js
│   ├─check-versions.js
│   ├─dev-client.js
│   ├─dev-server.js
│   ├─utils.js
│   ├─vue-loader.conf.js
│   ├─webpack.base.conf.js
│   ├─webpack.dev.conf.js
│   ├─webpack.prod.conf.js
│   └─webpack.test.conf.js
├─config
│   ├─dev.env.js
│   ├─index.js
│   ├─prod.env.js
│   └─test.env.js
├─...
└─package.json
以上是关于bulid与run的所有文件

指令分析

package.json里面

"dev": "node build/dev-server.js",

"build": "node build/build.js",

 

意思:运行”npm run dev”的时候执行的是build/dev-server.js文件,

运行”npm run build”的时候执行的是build/build.js文件。

build文件夹分析

build/dev-server.js

npm run dev 执行的文件build/dev-server.js文件,执行了:

检查node和npm的版本
引入相关插件和配置
创建express服务器和webpack编译器
配置开发中间件(webpack-dev-middleware)和热重载中间件(webpack-hot-middleware)
挂载代理服务和中间件
配置静态资源
启动服务器监听特定端口(8080)
自动打开浏览器并打开特定网址(localhost:8080)

说明: express服务器提供静态文件服务,不过它还使用了http-proxy-middleware,一个http请求代理的中间件。前端开发过程中需要使用到后台的API的话,可以通过配置proxyTable来将相应的后台请求代理到专用的API服务器。

build/webpack.base.conf.js

dev-server依赖的webpack配置是webpack.dev.conf.js文件,

测试环境下使用的是webpack.prod.conf.js

webpack.dev.conf.js中又引用了webpack.base.conf.js

webpack.base.conf.js主要完成了下面这些事情:

  1. 配置webpack编译入口

  2. 配置webpack输出路径和命名规则

  3. 配置模块resolve规则

  4. 配置不同类型模块的处理规则

这个配置里面只配置了.js、.vue、图片、字体等几类文件的处理规则,如果需要处理其他文件可以在module.rules里面配置。

build/webpack.dev.conf.js

在webpack.base.conf的基础上增加完善了开发环境下面的配置,主要包括下面几件事情:

将hot-reload相关的代码添加到entry chunks
合并基础的webpack配置
使用styleLoaders
配置Source Maps
配置webpack插件

build/check-versions.js和build/dev-client.js

最后是build文件夹下面两个比较简单的文件,

dev-client.js似乎没有使用到,代码也比较简单,这里不多讲。

check-version.js完成对node和npm的版本检测

build/utils.js和build/vue-loader.conf.js

webpack配置文件中使用到了utils.js和vue-loader.conf.js这两个文件,utils主要完成下面3件事:

配置静态资源路径
生成cssLoaders用于加载.vue文件中的样式
生成styleLoaders用于加载不在.vue文件中的单独存在的样式文件


vue-loader.conf则只配置了css加载器以及编译css之后自动添加前缀。

build/build.js

构建环境下的配置,

build.js主要完成下面几件事:

loading动画
删除创建目标文件夹
webpack编译
输出信息

build/webpack.prod.conf.js

构建的时候用到的webpack配置来自webpack.prod.conf.js,该配置同样是在webpack.base.conf基础上的进一步完善。主要完成下面几件事情:

合并基础的webpack配置
使用styleLoaders
配置webpack的输出
配置webpack插件
gzip模式下的webpack插件配置
webpack-bundle分析
说明: webpack插件里面多了丑化压缩代码以及抽离css文件等插件。

config文件夹分析

config/index.js

config文件夹下最主要的文件就是index.js了,

在这里面描述了开发和构建两种环境下的配置,前面的build文件夹下也有不少文件引用了index.js里面的配置。

config/dev.env.js、config/prod.env.js和config/test.env.js

这三个文件就简单设置了环境变量而已,没什么特别的。

这是webpack的基本入门,webpack还有很多插件,还需要去探索

后面写这几个文件的源码解释。