做为SQL存储过程和.NET的新手,下面的指导还是很有用的,自己这一段刚刚接触这些东西,搜集了一些相关的东西,能使新手较容易上手,当然啦,要精通和熟练应用,还是要看更多更深的资料的,高手请不要见笑。 以下内容均来自网络,只供参考学习: -------- 存储过程与SQL语句的恩怨情仇 程序员说:存储过程还是SQL语句,这是一个问题。 江湖现在有三个流派,一个是SQL语句流的,崇尚使用SQL语句,一派是存储过程派的,崇尚用存储过程说话,还有一派是中庸派的,讲求和谐,所以也就前两派吵得厉害,中庸派的看热闹。现在SQL派的有Nhibernate为首的众多ORM助阵,最近风生水起比较得意,存储过程派也有自己的杀手秘籍,两派互不相让,争斗由来已久。 存储过程派的追求速度,所谓天下无功无坚不破,唯快不破,这也是存储过程派的人行走江湖的最大本钱。之前存储过程派的攻击SQL语句派的还有一个秘籍就是安全,不过现在都没人用连接String的动态SQL的了,这招也就失效了。 SQL语句派是资格很老的流派,但是新手居多,老资格很多投奔敌营存储过程派了。Java帮的人很多都是SQL语句派的,而存储过程派的以微软帮的居多。 不过存储过程派也有软肋,可移植性就是其一,还有一点就是可扩展性,因为一般大型的Web应用程序都是多Web服务器,然后用双数据库服务器做双机热备,其中一台开机,但是是闲置的,这里只是解决单点故障的问题,但是形成了多Web应用服务器,单数据库服务器的情况,如果所有的运算都用存储过程实现,那么会造成数据库服务器负担过重,而Web服务器负荷不足的情况,而扩展数据库服务器的话就会非常的麻烦,而且投资较大,程序也需要改,而投资Web服务器就相对便宜而且扩容更加简单。 人在江湖漂哪有不挨刀,所以中庸一点比较保险,我比较倾向于用把较多的负担放到程序里来,而降低数据库得负担,因为只要数据库扛得住,再增加Web服务器那是比较容易的,但是一旦数据库服务器扛不住了我们就只有哭了。一般报表阿,还有一些结果集比较复杂的我就用存储过程来包装,一般的查询和CUID操作我都是找个ORM来搞定。 其实主要是在说存储过程的软肋。 1)从部署上看,存储过程要比sql难 2) 从性能看,存储过程要比SQL高 3) 从安全性将,存储过程比SQL防注入 过程可以减少网络数据传输量,把计算都放在服务器上 前端程序可以直接访问数据库的表,可以直接用SQL语言直接对数据库的表进行读写操作; 为安全,可以编程,使用存储过程进行数据表的读写操作,而前端程序直接访问这些存储过程,而不是数据库的表; 更安全的方法是:在前端程序和数据库之间,增加数据库访问层;前端将数据的读写请求提交给中间层,有中间层与数据库连接进行数据库的实际操作,将结果送给前端,这种方式可以避免前端机器直接连接到数据库的可能,数据库更安全。 C#两种不同的存储过程调用方法 ==================================================== 两种不同的存储过程调用方法 为了突出新方法的优点,首先介绍一下在.NET中调用存储过程的“官方”方法。另外,本文的所有示例程序均工作于SqlServer数据库上,其它情况类似,以后不再一一说明。本文所有例子均采用C#语言。 要在应用程序中访问数据库,一般性的步骤是:首先声明一个数据库连接SqlConnection,然后声明一个数据库命令SqlCommand,用来执行 SQL语句和存储过程。有了这两个对象后,就可以根据自己的需要采用不同的执行方式达到目的。需要补充的是,不要忘记在页面上添加如下的引用语句: using System.Data.SqlClient。 就执行存储过程来说,如果执行的是第一类存储过程,那么就要用一个 DataAdapter将结果填充到一个DataSet中,然后就可以使用数据网格控件将结果呈现在页面上了;如果执行的是第二和第三种存储过程,则不需要此过程,只需要根据特定的返回判定操作是否成功完成即可。 (1)执行一个没有参数的存储过程的代码如下: SqlConnection conn=new SqlConnection(“connectionString”); SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(); da.SelectCommand.Connection = conn; da.SelectCommand.CommandText = "NameOfProcedure"; da.SelectCommand.CommandType = CommandType.StoredProcedure; 然后只要选择适当的方式执行此处过程,用于不同的目的即可。 (2)执行一个有参数的存储过程的代码如下(我们可以将调用存储过程的函数声明为ExeProcedure(string inputdate)): SqlConnection conn=new SqlConnection(“connectionString”); SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(); da.SelectCommand.Connection = conn; da.SelectCommand.CommandText = "NameOfProcedure"; da.SelectCommand.CommandType = CommandType.StoredProcedure; (以上代码相同,以下为要添加的代码) param = new SqlParameter("@ParameterName", SqlDbType.DateTime); param.Direction = ParameterDirection.Input; param.Value = Convert.ToDateTime(inputdate); da.SelectCommand.Parameters.Add(param); 这样就添加了一个输入参数。若需要添加输出参数: param = new SqlParameter("@ParameterName", SqlDbType.DateTime); param.Direction = ParameterDirection.Output; param.Value = Convert.ToDateTime(inputdate); da.SelectCommand.Parameters.Add(param); 若要获得参储过程的返回值: param = new SqlParameter("@ParameterName", SqlDbType.DateTime); param.Direction = ParameterDirection.ReturnValue; param.Value = Convert.ToDateTime(inputdate); da.SelectCommand.Parameters.Add(param); 从上面的代码我们可以看出,当存储过程比较多或者存储过程的参数比较多时,这种方法会大大影响开发的速度;另外一方面,如果项目比较大,那么这些用于数据库逻辑的函数在以后的维护中也是一个很大的负担。那么,有没有一种改进的方法可以解决这个问题呢?想到在执行没有参数的存储过程时只需要传入一个存储过程的名字就可以调用相应的存储过程,而且在SqlServer数据库中我们可以直接在查询分析器中敲入“存储过程名(参数列表)”样的字符串就可以执行存储过程,那么,是否可以把这种思想应用到应用程序中呢? 于是在编译器中键入相应代码。这些代码是在调用不带参数的存储过程的代码的基础上改的。具体代码如下: SqlConnection conn=new SqlConnection(“connectionString”); SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand(); da.SelectCommand.Connection = conn; da.SelectCommand.CommandText = "NameOfProcedure(’para1’,’para2’,para3)"; da.SelectCommand.CommandType = CommandType.StoredProcedure; 为了使代码更具有代表性,要调用的存储过程的第一个和第二个参数都为字符串类型,第三个参数为整型。执行以后发现,完全可以达到预期的效果! SQL Server 2005帮助文档中关于存储过程返回值使用的例子和说明 RETURN 语句无条件终止查询、存储过程或批处理。存储过程或批处理中 RETURN 语句后面的语句都不执行。 当在存储过程中使用 RETURN 语句时,此语句可以指定返回给调用应用程序、批处理或过程的整数值。如果 RETURN 未指定值,则存储过程返回 0。 大多数存储过程按常规使用返回代码表示存储过程的成功或失败。没有发生错误时存储过程返回值 0。任何非零值表示有错误发生。例如: USE AdventureWorks; GO -- Create a procedure that takes one input parameter -- and returns one output parameter and a return code. CREATE PROCEDURE SampleProcedure @EmployeeIDParm INT, @MaxTotal INT OUTPUT AS -- Declare and initialize a variable to hold @@ERROR. DECLARE @ErrorSave int; SET @ErrorSave = 0; -- Do a SELECT using the input parameter. SELECT c.FirstName, c.LastName, e.Title FROM HumanResources.Employee AS e JOIN Person.Contact AS c ON e.ContactID = c.ContactID WHERE EmployeeID = @EmployeeIDParm; -- Save any nonzero @@ERROR value. IF (@@ERROR <> 0) SET @ErrorSave = @@ERROR; -- Set a value in the output parameter. SELECT @MaxTotal = MAX(TotalDue) FROM Sales.SalesOrderHeader; IF (@@ERROR <> 0) SET @ErrorSave = @@ERROR; -- Returns 0 if neither SELECT statement had -- an error, otherwise returns the last error. RETURN @ErrorSave; GO 执行存储过程的 Transact-SQL 批处理或存储过程可以将返回代码检索到整数变量中: DECLARE @ReturnStatus int; DECLARE @MaxTotalVariable int; DECLARE @MaxTotal int; EXECUTE @ReturnStatus = SampleProcedure @EmployeeIDParm = 65 ,@MaxTotal = @MaxTotalVariable OUTPUT; PRINT ' '; PRINT 'Return code = ' + CAST(@ReturnStatus AS CHAR(10)); PRINT 'Maximum Order Total = ' + CAST(@MaxTotalVariable AS CHAR(15)); GO 调用存储过程的应用程序可以将返回代码所对应的参数标记与整型变量绑定。