机房收费系统(VB.NET)——存储过程实战
背景:机房收费系统中有一个注册的功能,原型图如下:
insert into T_Card(cardNumber,balance,type,stuNumber,status,isChecked ) values(@cardNumber,@balance,@type,@stuNumber,@status,@isChecked ) 2:向学生表T_Student添加记录 insert into T_Student (stuNumber,stuName,stuSex,stuMajor,stuGrade,stuClass,comment ) values (@stuNumber,@stuName,@stuSex,@stuMajor,@stuGrade,@stuClass,@comment ) 3:向充值表T_Register添加记录 insert into chargesystem.dbo.T_Recharge (userID,cardNumber,rechargeCash,rechargeDate,rechargeTime,isChecked )values(@userID,@cardNumber,CONVERT(varchar,getdate(),120),GETDATE(),108),'未结账') 存储过程的使用对于上面的需求,如果用存储过程,在数据库里建立存储过程之后,在代码里只需负责直接执行这个存储过程即可,而不用连续多次连接、操作数据库。一、建立存储过程建立存储过程有两种方法(因为系统用的数据库为SqlServer2008,所以这里以此为例):(1)、手动建立存储过程:对象资源管理器中:数据库→ChargeSystem(数据库名称)→可编程性→右键“存储过程”→新建存储过程 (2)、SQL语句添加存储过程直接新建查询,在代码编辑窗口编写存储过程SQL代码,基本语法为:CREATE PROCEDURE PROC_NAME @[参数名] [类型],@[参数名] [类型]…… AS BEGIN [过程体]......... END
CREATE PROCEDURE PROC_Register -- 定义参数 @cardNumber varchar(6),@balance decimal(5,1),@type nvarchar(20),@status nvarchar(50),@isChecked nvarchar(10),@stuNumber varchar(18),@stuName nvarchar(10),@stuSex varchar(6),@stuMajor nvarchar(30),@stuGrade nvarchar(20),@stuClass nvarchar(20),@comment nvarchar(100),@userID varchar(18) AS BEGIN --向表中插入数据 insert into ChargeSystem .dbo.T_Card(cardNumber,@isChecked ) insert into ChargeSystem .dbo.T_Student (stuNumber,@comment ) insert into chargesystem.dbo.T_Recharge (userID,CONVERT(char(10),'未结账') END 注意:无论是用哪种方式建立的存储过程,都需要点击执行来存到服务器里,才可以通过以后的调用来执行,单纯地保存(ctrl+C)只是把这个存储过程文件保存在本地,而不会存入数据库服务器中。 当建立好存储过程时,可以新建查询执行“exec 存储过程名 @参数1=值1,@参数2=值2……”来验证存储过程是否正确。 二、代码中调用存储过程调用存储过程跟执行SQL语句的方式大同小异,需要注意的是,执行SQL语句时,命令对象Command的CommandType的值为CommandType.Text,而执行存储过程时,CommandType的值为CommandType.StoredProcedure。在本例中具体代码为:
Public Class SqlServerRegisterDAL : Implements IDAL.IRegister Public Function Insert(ByVal enCard As Entity.CardEntity,ByVal enStudent As Entity.StudentEntity,ByVal userID As String) As Boolean Implements IDAL.IRegister.Insert Dim sqlHelper As New SqlHelper '定义SqlHelper实例 Dim cmdType As CommandType = CommandType.StoredProcedure '定义数据库命令类型 Dim cmdText As String = "PROC_Register" '数据库执行字符串 Dim parameters As SqlParameter() '定义参数数组,负责向存储过程中的变量传值 '为参数数组中的参数一一赋值 parameters = {New SqlParameter("@cardNumber",enCard.CardNumber),New SqlParameter("@balance",enCard.Balance),New SqlParameter("@type ",enCard.CardType),New SqlParameter("@status",enCard.Status),New SqlParameter("@isChecked",enCard.IsChecked),New SqlParameter("@stuNumber",enStudent.StuNumber),New SqlParameter("@stuName",enStudent.StuName),New SqlParameter("@stuSex",enStudent.StuSex),New SqlParameter("@stuMajor",enStudent.StuMajor),New SqlParameter("@stuGrade",enStudent.StuGrade),New SqlParameter("@stuClass",enStudent.StuClass),New SqlParameter("@comment",enStudent.StuComment),New SqlParameter("@userID",userID)} '判断是否有查询结果 If sqlHelper.ExecuteNonQuery(cmdText,cmdType,parameters) Then Return True Else Return False End If End Function End Class SqlHelper代码:
Public Class SqlHelper '从配置文件中获取连接字符串的值 Dim strConnection As String = ConfigurationSettings.AppSettings("strConnection") '创建数据库连接对象conn Dim conn As SqlConnection '创建数据库操作类cmd Dim cmd As New SqlCommand ''' <summary> ''' 构造函数,实例化类时就初始化数据库连接对象 ''' </summary> ''' <remarks></remarks> Public Sub New() conn = New SqlConnection(strConnection) End Sub ''' <summary> ''' 关闭释放SqlCommand对象 ''' </summary> ''' <param name="cmd">需要关闭的SqlCommand对象</param> ''' <remarks>cmd.Dispose()直接释放command资源,不知这么做对系统性能怎么样,先这么着,以后再继续优化</remarks> Public Sub CloseCommand(ByVal cmd As SqlCommand) If Not IsNothing(cmd) Then cmd.Dispose() cmd = Nothing End If End Sub ''' <summary> ''' 关闭数据库连接 ''' </summary> ''' <param name="conn">需要关闭的SqlConnection对象</param> ''' <remarks>关闭数据库连接,但并没有释放,而是存储在连接池中,需要的时候还可以通过Open()方法打开连接</remarks> Public Sub CloseConnection(ByVal conn As SqlConnection) If Not IsNothing(conn) Then conn.Close() End If End Sub ''' <summary> ''' 有参数的 增 删 改 操作 ''' </summary> ''' <param name="cmdText">需要执行的SQL命令</param> ''' <param name="cmdType">所执行命令的,一般是sql语句、存储过程或表</param> ''' <param name="sqlParameters">参数数组</param> ''' <returns>返回受影响的行数 类型为整型</returns> ''' <remarks></remarks> Public Function ExecuteNonQuery(ByVal cmdText As String,ByVal cmdType As String,ByVal sqlParameters As SqlParameter()) As Integer Try conn.Open() '打开数据库连接 cmd.CommandText = cmdText '设置查询语句 cmd.CommandType = cmdType '设置一个值,解释cmdType(如果值为StoredProcedure时,调用的是存储过程) cmd.Connection = conn '设置连接 cmd.Parameters.AddRange(sqlParameters) '传入参数 Dim affectedRows As Integer affectedRows = cmd.ExecuteNonQuery Return affectedRows '返回执行所受影响行数 Catch ex As Exception MsgBox(ex.Message,MsgBoxStyle.OkOnly,"温馨提示") Return 0 '如果出错,则返回0 Finally cmd.Parameters.Clear() '清楚参数 Call CloseCommand(cmd) '关闭并释放Command Call CloseConnection(conn) '关闭连接conn End Try End Function End Class 为什么要使用存储过程注册学生卡号在这个系统中不算个大模块,但这个小小的需求,需要与数据库中三个表的数据打交道,而在以往的操作,竟然连了三次数据库,执行了三次SQL语句。 这样频繁地打开与关闭与数据库的连接,需要消耗大量系统资源,降低执行速度。这时就需要考虑用存储过程来代替执行如此之多的SQL语句。 1、一般SQL语句每执行一次就需要编译一次,而存储过程只是在创造时进行编译,以后每次执行都不需要再进行编译。 2、存储过程就是相当于把多个需要执行的SQL语句集合起来,变成一条SQL语句,当然就只需连接和执行一次就可以得到结果。 3、安全性高。可以指定存储过程的使用权,防止SQL注入。 4、系统升级、维护比较方便。 总结: ★当涉及到多个SQL语句执行,需要多次连接数据库,或者需要对多张表进行处理时,可以将这些操作封装在一起,即创建存储过程,以后每次需要的时候直接调用执行,即可执行所有的操作,避免了多次打开、关闭数据库连接。 ★当涉及到比较复杂的需求时(比如机房收费系统中的下机结算消费金额就可以采用存储过程),比如排序、计算等等,可以把数据直接传到存储过程,一系列操作在数据库服务器里进行,减小了客户端与服务器之间的数据流量,同时还保证了系统的安全性。
到了这里大家脑子里可能会有个问题:既然让一个存储过程执行多个任务,那么万一在执行的过程中,这些任务中的一个或者几个任务没有完成,该如何是好?这时事务就派上用场了…快去实践吧… (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |