1、存储过程的概念
存储过程是一组为了完成特定功能的SQL语句集,存储在数据库中,经过第一次调用编译后,再次调用不需要编译。用户通过指定存储过程的名字并给出参数 (如果该存储过程带有参数) 来执行它 , 存储过程是数据库中的一个重要对象 ; 存储过程中可以包含 逻辑控制语句 和 数据操纵语句 , 它可以接受参数 , 输出参数 , 返回单个或多个结果集以及返回值
2、存储过程的优缺点
优点:
1、运行速度:对于很简单的sql,存储过程没有什么优势。对于复杂的业务逻辑,因为在存储过程创建的时候,数据库已经对其进行了一次解析和优化。存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接调用,所以执行速度会比普通sql快。
2、可维护性:的存储过程有些时候比程序更容易维护,这是因为可以实时更新DB端的存储过程。 有些bug,直接改存储过程里的业务逻辑,就搞定了。
3、 可扩展性:应用程序和数据库操作分开,独立进行,而不是相互在一起。方便以后的扩展和DBA维护优化
4、增强安全性 :
通过向用户授予对存储过程 (而不是基于表) 的访问权限 , 它们可以提供对特定数据的访问 ;
提高代码安全 , 防止 SQL注入 (但未彻底解决 , 例如将数据操作语言 DML 附加到输入参数)
缺点:
1、可移植性差 , 由于存储过程将应用程序绑定到 Server , 因此使用存储过程封装业务逻辑将限制应用程序的可移植性 ; 如果应用程序的可移植性在您的环境中非常重要 , 则将业务逻辑封装在不特定于 RDBMS 的中间层中可能是一个更佳的选择 ;
3、创建存储过程的基本语法
创建
if (exists (select * from sys.objects where name = 'pro_name' and type='p'))
drop proc pro_name
go
create proc pro_name
@param_name param_type [=default_value]
as
begin
sql语句
end
param_type表示参数类型,后面是参数的值,[ ]表示非必写内容。
sys.objects存储的是本数据库中的信息,不仅仅存储表名,还有存储过程名 、视图名、触发器等等。
SQL Server 实用工具将 GO 解释为应将当前的 Transact-SQL 批处理语句发送给 SQL Server 的信号。当前批处理语句是自上一 GO 命令后输入的所有语句,若是第一条 GO 命令,则是从特殊会话或脚本的开始处到这条 GO 命令之间的所有语句。
调用
exec dbo.存储过程名 参数值;
一般在执行存储过程是,最好加上架构名称,例如 dbo.USP_GetAllUser 这样可以可以减少不必要的系统开销,提高性能。 因为如果在存储过程名称前面没有加上架构名称,SQL SERVER 首先会从当前数据库sys schema(系统架构)开始查找,如果没有找到,则会去其它schema查找,最后在dbo架构(系统管理员架构)里面查找。
一个简单的根据ID查询用户表的存储过程
if (exists(select * from sys.objects where name='GetUser'))
drop proc GetUser
go
create proc GetUser
@id int output, //output意为该参数可以输出
@name varchar(20) out //out为输出参数
as
begin
select @id=Id,@name=Name from UserInfo where Id=@id
end
go
declare //declare用于声明参数
@name varchar(20),
@id int;
set @id=3; //赋值
exec dbo.GetUser @id,@name out;
select @id,@name;
分页获取数据的存储过程
if (exists(select * from sys.objects where name='GetUserByPage'))
drop proc GetUserByPage
go
create proc GetUserByPage
@pageIndex int,
@pageSize int
as
declare
@startIndex int,
@endIndex int;
set @startIndex = (@pageIndex-1)*@pageSize+1;
set @endIndex = @startIndex + @pageSize -1 ;
begin
select Id,Name from
(
select *,row_number()over (order by Id)as number from UserInfo
)t where t.number>=@startIndex and t.number<=@endIndex
end
go
exec dbo.GetUserByPage 2,4;
事务的应用实例
if (exists(select * from sys.objects where name='JayJayToTest'))
drop proc JayJayToTest
go
create proc JayJayToTest
@GiveMoney int,
@UserName nvarchar(20)
as
beginset nocount on;
begin tran;
begin try
update BankTest set Money = Money-@GiveMoney where Name=@UserName;
update BankTest set Money = Money+@GiveMoney where Name='test';
commit;
end try
begin catch
rollback tran;
print ('发生异常,事务进行回滚');
end catch
end
go
exec JayJayToTest 10,'jayjay'
以上文章整理来源 https://www.cnblogs.com/sunniest/p/4386296.html
3.Net调用存储过程
1.无参数无返回值的存储过程
无返回值的存储过程可以执行增加记录、删除记录、修改记录等数据库操作。使用命令对象执行无返回值存储过程和无返回值的Sql语句执行方式基本相同,都是使用ExecuteQuery()。
Create Proc ch_Person
as
Update Person
Set psnAddress=’乞力马扎罗’
Where psnName=’帕瓦罗蒂’
Go
要通过C#执行该存储过程,需要创建一个SqlCommand类的命令对象,然后修改命令对象的类型属性CommandType为存储过程类型,并设置命令对象的CommandText为存储过程的名字,然后通过ExecuteNonQuery()方法执行存储过程即可:
SqlConnection cn=new SqlConnection("server=.;database=test;uid=sa;pwd=123456");
try
{
cn.Open();
SqlCommandcmd=cn.CreateCommand();
//设置命令类型为存储过程
cmd.CommandType=CommandType.StoreProcedure;
//设置存储过程的名字
cmd.CommandText="ch_Person";
//执行存储过程
cmd.ExecuteNonQuery();
}
catch(SqlExecption ex)
{
//数据库出错信息提示
}
finally
{
cn.Close();
}
2.带参数
Create Proc ch_Person
@p_psnName NvarChar(5),
@p_psnAddress NvarChar(50)
As
Update Person
Set psnAddress=@p_psnAddress
Where psnName=@p_psnName
Go
调用这个存储过程又需要用到命令对象中的参数属性Parameters,只需要在这个参数集合里加入存储过程的参数定义并设置其值就可以了,代码如下:
SqlConnection cn=new SqlConnection("server=.;database=test;uid=sa;pwd=123456");
try
{
cn.Open();
SqlCommandcmd=new SqlCommand("ch_Person",cn);
cmd.CommandType=CommandType.StoredProcedure;
//加入参数对象,并设置其值
cmd.Parameters.Add("@p_psnName",SqlDbType.NVarChar).Value="帕瓦罗蒂";
cmd.Parameters.Add("@p_psnAddress",SqlDbType.NVarChar).Value="日本广岛";
//执行存储过程
cmd.ExecuteNonQuery();
}
catch(SqlException ex)
{
//操作数据库出错信息处理
}
finally
{
cn.Close();
}
- 调用带返回值的存储过程
Create Proc gt_Address
@p_psnName NvarChar(5) //请输入姓名
@g_psnAddress NvarChar(5)OutPut //返回此人的地址
As
Select@g_psnAddress=psnAddress From Person
WherepsnName=@p_psnName
If@@Error<>0
Return-1 //如果查询语句出错返回-1
Else
Return 0
Go
对于带参数的存储过程,不管是输入参数还是输出参数,实际上有一种简单的方式创建参数,就是使用系统类SqlCommandBuilder的静态方法DeriveParameters自动生成参数。使用DeriveParameters方法可以从SqlCommand中指定的存储过程中检索参数信息并填充到该SqlCommand对象的Parameters集合里。我们使用DeriveParameters方法重新实现上面的存储过程调用如下:
SqlConnection cn=new SqlConnection("server=.;database=test;uid=sa;pwd=123456");
try
{
cn.Open();
SqlCommandcmd=new SqlCommand("gt_Address",cn);
cmd.CommandType=CommandType.StoredProcedure;
//为命令对象生成参数
SqlCommandBuilder.DeriveParameters(cmd);
//设置输入参数的值
cmd.Parameters.Add("@p_psnName",SqlDbType.NvarChar).Value="帕瓦罗蒂";
//执行存储过程
cmd.ExecuteNonQuery();
int res=(int)cmd.Parameters["@Return"].Value;
string address=(string)cmd.Parameters["@p_psnAddress"].Value;
Console.WriteLine("返回值:{0},地址:{1}",res,address);
}
catch(SqlException ex)
{
//数据库出错信息报告
}
finally
{
cn.Close();
}