当我们在写一个数据库操纵语句时,如果只涉及到一个表的增删改查,那么非常容易,直接在D层写相应的代码就好了,但是如果我们需要同时操作多张表呢?在D层一行一行的写操作语句是不是非常麻烦,而且逻辑也非常不清楚呢?这时候,存储过程的作用就体现出来了。
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。
通俗点说,就是在sql数据库中,完成了D层的操作,这样做的好处很多,比如经过一次编译再次调用时可直接使用,不必二次编译,减轻系统负担,简洁,明了。但是我又想到,如果要换一个差别很大的数据库,工作量是不是又多了呢?这个暂且不讨论,我们就知道它很好用就够了。
数据库中:
USE [ChargeSed_sys] GO /****** Object: StoredProcedure [dbo].[Register] Script Date: 02/15/2016 14:29:12 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[Register] -- Add the parameters for the stored procedure here --定义变量 @CardNo char(11), @AddMoney int, @ChargeDate date, @ChargeTime time(0), @Status nchar(10), @IsCheck nchar(10), @Head nchar(10), @StudentNo char(11), @StudentName nchar(10), @Sex nchar(10), @Department nchar(10), @Major nchar(10), @Grade nchar(10), @Class nchar(10), @Explain nchar(20), @RegisterDate date, @Cash int, @Type nchar(10) AS BEGIN declare @error int --声明变量(事务) set @error = 0 --赋值(事务) BEGIN TRANSACTION --事务开始语句 --添加学生表 insert into T_STUDENTS (StudentNo,StudentName,Sex,Department,Major,Grade,Class,Explain) values (@StudentNo,@StudentName,@Sex,@Department,@Major,@Grade,@Class,@Explain) set @error = @error + @@ERROR --事务 --添加卡表 insert into T_CARDS (CardNo,StudentNo,RegisterDate,Cash,Type,Status,IsCheck) values (@CardNo,@StudentNo,@RegisterDate,@Cash,@Type,@Status,@IsCheck) set @error = @error + @@ERROR --事务 --添加充值表 insert into T_RECHARGE (CardNo,AddMoney,ChargeDate,ChargeTime,Status,Head,IsCheck) values(@CardNo,@AddMoney,@ChargeDate,@ChargeTime,@Status,@Head,@IsCheck) set @error =@error + @@ERROR --事务 if @error <> 0 ROLLBACK --发生错误回滚 else COMMIT --不发生错误插入 ENDD层中:
首先要参数赋值,存储过程中出现的参数,都需要赋值,如果需要不需赋值的内部变量,要用declare关键字声明。
string sql = "Register"; bool flag = SqlDAL.SQLHelper.ExecuteNonQuery(sql, CommandType.StoredProcedure, sqlParams);在这里,Register是我的存储过程名字,之前的CommandType.Text要改为CommandType.StoredProcedure,具体这两个属性的意思直接将鼠标放到代码中就会显示出来。
注意:这个是经过我一次编译的存储过程,如果要创建存储过程,就要相应的将ALTER关键字改为创建的关键字CREATE。
大家看我的代码,发现里面每句操纵语句后面都跟了一行事务语句,我们都学过事务,这里,我们主要用了事务的一个重要特性——原子性。也就是说,这些代码,要么都执行,要么都不执行。这就保证了我们这些代码的同步进行。
既然说到了事务,那么我们就再来详细了解一下事务。
1、事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性。
2、事务通常是以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。
3、COMMIT表示提交,即提交事务的所有操作。具体地说就是将事务中所有对数据库的更新写回到磁盘上的物理数据库中去,事务正常结束。
4、ROLLBACK表示回滚,即在事务运行的过程中发生了某种故障,事务不能继续进行,系统将事务中对数据库的所有以完成的操作全部撤消,滚回到事务开始的状态。
在存储过程中,很多人会问,我怎么验证我的存储过程是否正确,难道还需要我在编译软件中用代码走一遍吗?并不需要,而且那样做,如果出现错误,我们并不会知道这个错误出现在存储过程中还是代码中,其实在sql server中自带执行功能,我们可以在数据库验证存储过程的正确与否:右键你的存储过程,单击“执行存储过程”,为你的变量相应赋值,确定,如果你的语句都正确的话,返回一个0,证明你的存储过程没有问题了。
如果我执行的是增删改的操作,那么不会返回表,如果是查,会返回查到的临时表,这是大家都知道的。但是我的重构需要一个功能,它返回的不是一张表,而是多个表中,每个表计算出一条数据,这几条数据综合而成的一张虚拟表,这该怎么办呢?我这里有一个办法:我想到,用select关键字可以返回表,那么,如果我在存储过程中定义几个不需要赋值的内部变量,将这些变量select出来,能不能成功呢?实践了一下,非常意外,我成功了。下面是我的代码:
select NumSellCard=@NumSellCard,NumBackCard=@NumBackCard,RechargeCash=@RechargeCash,BackCash=@BackCash,Cash=@Cash
没错,就是结账时候需要返回的那几个整合数据,我用这种方法将这些数据整合成一张表返回到D层。但是我不知道这样做对不对,符不符合要求,欢迎大家提出宝贵建议。
存储过程虽然很简单,但它包含的内容确实不少,我们应该认真面对每一个问题,不管它难以与否,我们都能从中学到很多,每解决一个问题,我们就离成功近了一步,加油。