过程

过程(又称存储过程)是事先编译好存储在数据库中的一组SQL的集合,调用过程可以简化应用程序开发人员的工作,减少与数据库服务器之间的通信,对于提升数据操作的性能也是有帮助的。其实迄今为止,我们使用的SQL语句都是针对一个或多个表的单条语句,但在实际开发中经常会遇到某个操作需要多条SQL语句才能完成的情况。例如,电商网站在受理用户订单时,需要做以下一系列的处理。

  1. 通过查询来核对库存中是否有对应的物品以及库存是否充足。
  2. 如果库存有物品,需要锁定库存以确保这些物品不再卖给别人, 并且要减少可用的物品数量以反映正确的库存量。
  3. 如果库存不足,可能需要进一步与供应商进行交互或者至少产生一条系统提示消息。
  4. 不管受理订单是否成功,都需要产生流水记录,而且需要给对应的用户产生一条通知信息。

我们可以通过过程将复杂的操作封装起来,这样不仅有助于保证数据的一致性,而且将来如果业务发生了变动,只需要调整和修改过程即可。对于调用过程的用户来说,过程并没有暴露数据表的细节,而且执行过程比一条条的执行一组SQL要快得多。

下面的过程实现了查询某门课程的最高分、最低分和平均分。

  1. drop procedure if exists sp_score_by_cid;
  2. delimiter $$
  3. create procedure sp_score_by_cid(
  4. courseId int,
  5. out maxScore decimal(4,1),
  6. out minScore decimal(4,1),
  7. out avgScore decimal(4,1)
  8. )
  9. begin
  10. select max(score) into maxScore from tb_record
  11. where cid=courseId;
  12. select min(score) into minScore from tb_record
  13. where cid=courseId;
  14. select avg(score) into avgScore from tb_record
  15. where cid=courseId;
  16. end $$
  17. delimiter ;
  18. call sp_score_by_cid(1111, @a, @b, @c);
  19. select @a, @b, @c;

说明:在定义过程时,因为可能需要书写多条SQL,而分隔这些SQL需要使用分号作为分隔符,如果这个时候,仍然用分号表示整段代码结束,那么定义过程的SQL就会出现错误,所以上面我们用delimiter 将整段代码结束的标记定义为,那么代码中的分号将不再表示整段代码的结束,整段代码只会在遇到end $$时才会执行。在定义完过程后,通过delimiter ;将结束符重新改回成分号(恢复现场)。

上面定义的过程有四个参数,其中第一个参数是输入参数,代表课程的编号,后面的参数都是输出参数,因为过程不能定义返回值,只能通过输出参数将执行结果带出,定义输出参数的关键字是out,默认情况下参数都是输入参数。

调用过程。

  1. call sp_score_by_cid(1111, @a, @b, @c);

获取输出参数的值。

  1. select @a as 最高分, @b as 最低分, @c as 平均分;

删除过程。

  1. drop procedure sp_score_by_cid;

在过程中,我们可以定义变量、条件,可以使用分支和循环语句,可以通过游标操作查询结果,还可以使用事件调度器,这些内容我们暂时不在此处进行介绍。虽然我们说了很多过程的好处,但是在实际开发中,如果过度的使用过程并将大量复杂的运算放到过程中,必然会导致占用数据库服务器的CPU资源,造成数据库服务器承受巨大的压力。为此,我们一般会将复杂的运算和处理交给应用服务器,因为很容易部署多台应用服务器来分摊这些压力。