Sql server存储过程
定义: Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。在数据量特别庞大的情况下利用存储过程能达到倍速的效率提升。源自百度百科
什么时候使用存储过程:
当一个事务涉及到多个SQL语句时或者涉及到对多个表的操作时就要考虑用存储过程;当在一个事务的完成需要很复杂的商业逻辑时(比如,对多个数据的操作,对多个状态的判断更改等)要考虑;还有就是比较复杂的统计和汇总也要考虑,但是过多的使用存储过程会降低系统的移植性。
存储过程的优缺点:
存储过程不仅仅适用于大型项目,对于中小型项目,使用存储过程也是非常有必要的。其威力和优势主要体现在:
1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
2.当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query,Delete 时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。这些操作,如果用程序来完成,就变成了一条条的 SQL 语句,可能要多次连接数据库。而换成存储,只需要连接一次数据库就可以了。
3.存储过程可以重复使用,可减少数据库开发人员的工作量。
4.安全性高,可设定只有某此用户才具有对指定存储过程的使用权。
优点:
1.速度快。尤其对于较为复杂的逻辑,减少了网络流量之间的消耗
有的过程和函数达到了几百行,一个微型编译器,相信用程序就更麻烦了。
2.写程序简单,采用存储过程调用类,调用任何存储过程都只要1-2行代码。
3.减少网络流量
4.提高系统安全性
可将存储过程作为用户存取数据的管道。可以限制用户对数据表的存取权限,建立特定的存储过程供用户使用,避免非授权用户对数据的访问,保证数据的安全。
缺点:
1.可移植性差,依赖于数据库厂商,难以移植(当一个小系统发展到大系统时,对数据库的要求也会发生改变)
2.难以调试,维护。业务逻辑大的时候,封装行不够,难调试,难以维护。
3.服务器不能负载均衡。复杂的应用用存储过程来实现,把业务处理的负担压在数据库服务器上了。没有办法通过中间层来灵活分担负载和压力,均衡负载等。
创建存储过程:
语法:
create procedure 存储过程名
参数
as
功能
--执行
exec 存储过程名 --调用语句为批处理的第一条语句时,可省略exec
示例Sql
不带参数的存储过程,创建一个存储过程,查看所有读者的姓名,可借本数,可借天数和已借书本数。
1. 不带参数的存储过程:创建一个存储过程,查看所有读者的姓名,可借天数和已借书本数。
create procedure usp_selectReader
as
select rdName,canLenQty,canLendDay,rdBorrowQty
from Reader, ReaderType
where Reader.rdType = ReaderType.rdType
-- 测试执行
exec usp_selelctReader
2.带输入参数和输出参数的存储过程:创建一个存储过程,输入读者的编号,输出该读者的姓名;
create procedure usp_getName
@rdID char(9),
@rdName varchar(20) output
as
select @rdName = rdName from Reader where rdID =@rdID
--测试执行
declare @rdName varchar(20)
exec usp_getName 'rd2018007',@rdName output
print @rdName
3.带输入参数的存储过程:创建一个存储过程,实现借书功能
alter procedure usp_borrow
@rdID char(9),
@bkID char(9),
@DateBorrow datetime,
@DateLendPlan datetime
as
begin tran
print 'begin tran'
begin try
--先判断图书状态
declare @bkState int
select @bkState = bkState from Book where bkID= @bkID
if(@bkState !=1)
raiserror('借书失败!!该图书不在馆内!',16,1);
else
begin
--判断读者借书是否已满
declare @rdBorrowQty int,@canLendQty int
select @canLendQty = canLenQty,@rdBorrowQty = rdBorrowQty from Reader,ReaderType
where rdID= @rdID and Reader.rdType = ReaderType.rdType;
if(@rdBorrwQty>=@canLendQty)
raiserror('借书失败,该读者借书已达上限',15,1)
else
begin
insert into Borrow(rdID,bkID,DateBorrow,DateLendPlan)
values(@rdID,@bkID, @DateBorrow,@DateLendPlan);
--修改图书状态
update Book set bkState =0 where bkID =@bkID;
--修改借书数量
update Reader set rdBorrowQty = rdBorrowQty+1 where rdID=@rdID;
print @rdID +'借' +@bkID+’成功!'
commit
print 'commit'
end
end
end try
begin catch
DECLARE @ErrorMessage NVARCHAR(4000)
select @ErrorMessage = ERROR_MESSAGE()
raiserror(@ErrorMessage,16,1)
rollback
print 'rollback'
end catch
--测试执行
declare @date datetime, @date_plan datetime
--获取当前时间为借书时间
set @date_plan =GETDATE()+10
exec usp_borrow 'rd2018001‘,’bk2018001',@date,@date_plan