![4369bb61cd2e060d12a3199ae25aa662.png](https://i-blog.csdnimg.cn/blog_migrate/8c1b015ba36d4e33c1b21c7f5a8d1fc1.jpeg)
MySQL触发器、存储过程实现
很多程序员在出去面试的时候都会存在这样一个问题,就是笔试题中对于sql语句的考察,很多关键字的写法忘记了甚至是完全没有用过,但是如果你能百度一下或者看一下之前写的代码又会瞬间想起来,这其实是一个比较尴尬的问题,仅仅的因为一个关键字就能否定你的sql能力或者代码能力吗?当然这是很片面的。但是sql的关键字又实在是太多,一个一个整理未免太多复杂,所以我这里不过多的介绍了,碰到了,自己查下资料即可。今天主要介绍的是触发器、存储过程的用法。
触发器的语法:
Delimiter $
Create trigger 触发器名称
After/before insert/update/delete on 表名
For each row #每隔一行执行一次动作,而不是对整个表(mysql中一般是固定写法)
Begin
sql语句
End$
Delimiter ;
解释一下,上面的语法意思:
在执行表的增删改之后或之前,完成事件的触发
下面,我们看下具体的例子,场景如下:
![27a40de679f5b41f068dff15e665f68c.png](https://i-blog.csdnimg.cn/blog_migrate/86428cb7183a1ce09b448d9e176b7843.png)
当我们向订单中插入数据时,商品表中的对应商品要减少对应的数量,这里我们使用触发器来实现;
触发器代码:
![5a78077022f941efaa5da2f8d0a7b894.png](https://i-blog.csdnimg.cn/blog_migrate/8c60ff7fb9fc4ba254d1b7701175d14d.png)
new.order_count 和new.g_id都是订单表中新传入的数据,根据新插的值进行动态更新
执行如下代码:
![5132f4aeee47e5769a796d402696462b.png](https://i-blog.csdnimg.cn/blog_migrate/1112ed9d40efb1cee5897e754d044687.png)
意为在我向订单表中插入数据之后,触发 更新商品表的sql语句
插入前:
![4e8e2c101c9b6a5e72d790f98887936f.png](https://i-blog.csdnimg.cn/blog_migrate/b4740a8ff7d5fa299da50db7934d4865.png)
插入后:
![e48f62af2be169a039f258572ce3b679.png](https://i-blog.csdnimg.cn/blog_migrate/c41462b228565d5f408898297ee27753.png)
到这里,触发器的实现就已经完全写完了。但是,这里还可能存在一种情况,用户如果不想买了,我们应该如何处理,你需要把订单表的记录删除,然后把对应的商品数量加回去。
触发器:
![3b5e60ff4e6330807fc01242aa28318d.png](https://i-blog.csdnimg.cn/blog_migrate/b02e036471202ff34ece9bcfeb453a3b.png)
需要注意的是我们这里不能再使用new.order_count 和new.g_id,而应该换成对应的old,因为我们要删除的信息不是新插入的,而是用的之前的,这一点应该是不难理解的。
执行如下代码:
![e1f9924e12569f6590e6fbc81287f549.png](https://i-blog.csdnimg.cn/blog_migrate/00f14118b069bc1a3cce47eff6304f71.png)
删除后:
![194e4a82a3ec92e62199c11a689978da.png](https://i-blog.csdnimg.cn/blog_migrate/4941fcfd5dfedb4d92d7da49ee08380a.png)
可以看到,此时的面包数量已经加回来了;
上述代码写得都是先执行增删改,再进行触发,下面我们演示先触发,再进行对应的增删改
结合具体实例:
用户在购买的时候,我们实际开发中需要先对商品数量进行判断,如果,商品库存不足或者小于订单购买量,此时应提示库存不足。
同样,需要用到before关键字,意为先触发事件,再进行增删改
触发器代码如图:
![fedab1890f49845c229127b75b0adcd7.png](https://i-blog.csdnimg.cn/blog_migrate/29f47c16ae8514bb62417e7c39f8888e.png)
执行下面代码:
![ef75bd5bbc748c0bda6f6e90baf5c5a1.png](https://i-blog.csdnimg.cn/blog_migrate/164a2902704a42e3ee3434d91ea2e503.png)
插入前:
![468420373ac693671acb26883792b241.png](https://i-blog.csdnimg.cn/blog_migrate/0dd241691ac42c34915cf977e98bbfa3.png)
插入后:
![0e4ca35c53f3c20b41f48d0c3d7f4094.png](https://i-blog.csdnimg.cn/blog_migrate/a4cb42e9009ec42695a9dfe34c077660.png)
可以看到,我们明明购买了10个,但是库存只有8个,所以经过判断我们最多只能购买8个,当然,这里呢,也会存在一个问题,这个sql里面的8写的并不规范,正常来讲,应该先查询数量,再判断,这里只是解释after和before的区别。
存储过程语法:
Create procedure 存储过程名称(in/out 参数名 参数类型)
Begin
带参数的Sql代码
End
Call 存储过程名称();#调用存储过程
![c274308d868188a0c7d35001d32674bb.png](https://i-blog.csdnimg.cn/blog_migrate/d7003cf70900f2022b8b1e72e32080b5.png)
查询结果:
![e9dc63f896d5c30732433449bd1910e8.png](https://i-blog.csdnimg.cn/blog_migrate/a5f772ba9ba56164fa0b80f3936e8fb2.png)
类似于java里面的一个方法,通过set来给参数赋值,调用方法,获得查询结果
另外,提一句,有的人用的declare 给参数赋值,不是用的set,区别是:declare设置的是局部变量,set设置的是全局变量,大家可以自己试试。
总结:看起来触发器和存储过程的区别不是很大,比如我用触发器实现的功能放在存储过程中运行也没有问题,那么这两者如何区分呢?首先,触发器的执行不需要手动去调用,只要执行对应的sql就可以完成相应的事件触发,而存储过程必须手动去调用,这里的存储过程其实更类似于我们java中的方法;事实上,在实际的开发中,一般的简易的sql根本没有必要写存储过程,存储过程一般用来实现比较复杂的查询逻辑,用的时候调用即可。
以上