zoukankan      html  css  js  c++  java
  • 机房收费系统(VB.NET)——存储过程实战

           
              最初接触存储过程是在耿建玲老师的视频里,当初仅仅是草草过了一遍。仅仅是有了个印象。知道了这个名词;大二时也有SqlServer数据库这门课,只是老师没讲,自己也没看;真正对存储过程的了解来自于自学考试中的《数据库系统原理》,在考试中,知道存储过程是干嘛的。在纸上怎么写,但从来没有在DBMS中亲手敲过。于是机房收费系统给了我这个机会。


           在这里不再过多叙述关于存储过程德基本知识,仅仅写一下在机房收费系统这个小项目中是怎样用到存储过程的。


           背景


           机房收费系统中有一个注冊的功能,原型图例如以下:

           
            
            注冊时。须要对数据库中的三个表进行更新(向卡表T_Card、学生表T_Student、充值表T_Register中分别新增一条记录),所以,运行时,假设用运行SQL语句的方式,那就须要运行三次SQL语句:


            1:向卡表T_Card加入记录

     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 ,@balance, CONVERT(varchar,getdate(),120),CONVERT(varchar,GETDATE(),108),'未结账')


            存储过程的使用

            对于上面的需求,假设用存储过程,在数据库里建立存储过程之后,在代码里仅仅需负责直接运行这个存储过程就可以,而不用连续多次连接、操作数据库。

            一、建立存储过程

            建立存储过程有两种方法(由于系统用的数据库为SqlServer2008,所以这里以此为例):
            (1)、手动建立存储过程
            对象资源管理器中:数据库→ChargeSystem(数据库名称)→可编程性→右键“存储过程”→新建存储过程

             
            新建的存储过程能够说是一个已经成型的存储过程德模板。我们仅仅需在上面改动一下存储过程名称、參数、运行语句等代码就OK了。

         

           (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 ,balance ,type ,stuNumber ,status ,isChecked ) values(@cardNumber ,@balance, @type ,@stuNumber ,@status ,@isChecked )
    	insert into ChargeSystem .dbo.T_Student (stuNumber,stuName,stuSex,stuMajor,stuGrade,stuClass  ,comment ) values (@stuNumber ,@stuName ,@stuSex ,@stuMajor ,@stuGrade ,@stuClass,@comment )
    	insert into chargesystem.dbo.T_Recharge (userID,cardNumber,rechargeCash ,rechargeDate ,rechargeTime ,isChecked )values(@userID,@cardNumber ,@balance, CONVERT(char(10),getdate(),120),CONVERT(varchar,GETDATE(),108),'未结账')
    END
    

                注意:不管是用哪种方式建立的存储过程。都须要点击运行来存到server里。才干够通过以后的调用来运行,单纯地保存(ctrl+C)仅仅是把这个存储过程文件保存在本地,而不会存入数据库server中。

           当建立好存储过程时,能够新建查询运行“exec 存储过程名 @參数1=值1,@參数2=值2……”来验证存储过程是否正确。

            二、代码中调用存储过程

            调用存储过程跟运行SQL语句的方式大同小异,须要注意的是,运行SQL语句时。命令对象Command的CommandType的值为CommandType.Text,而运行存储过程时。CommandType的值为CommandType.StoredProcedure。
            在本例中详细代码为:


            D层代码:       

    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语句运行,须要多次连接数据库。或者须要对多张表进行处理时,能够将这些操作封装在一起,即创建存储过程。以后每次须要的时候直接调用运行。就可以运行全部的操作,避免了多次打开、关闭数据库连接。

           ★ 当涉及到比較复杂的需求时(比方机房收费系统中的下机结算消费金额就能够採用存储过程)。比方排序、计算等等。能够把数据直接传到存储过程,一系列操作在数据库server里进行,减小了client与server之间的数据流量,同一时候还保证了系统的安全性。

      

           到了这里大家脑子里可能会有个问题:既然让一个存储过程运行多个任务,那么万一在运行的过程中,这些任务中的一个或者几个任务没有完毕。该怎样是好?这时事务就派上用场了…快去实践吧…

           



            
  • 相关阅读:
    ABAP学习(10):ALV显示之function alv
    ABAP学习(11):ALV显示之OO ALV使用示例
    ABAP学习(3):屏幕显示
    ABAP学习(6):ABAP GUI和开发工具
    ABAP学习(9):时间日期操作
    ABAP学习(8):操作EXCEL
    ABAP学习(2):控制语句
    ABAP学习(5):数据库语句
    ABAP学习(4):内表
    编程经验:高性能.NET WEB开发(1)http压缩
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5325458.html
Copyright © 2011-2022 走看看