机房收费系统(VB.NET)——存储过程实战

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

      背景:


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


49.png


       注册时,需要对数据库中的三个表进行更新(向卡表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(数据库名称)→可编程性→右键“存储过程”→新建存储过程


50.png


       新建的存储过程可以说是一个已经成型的存储过程德模板,我们只需在上面修改一下存储过程名称、参数、执行语句等代码就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


           注意:无论是用哪种方式建立的存储过程,都需要点击执行来存到服务器里,才可以通过以后的调用来执行,单纯地保存(ctrl+C)只是把这个存储过程文件保存在本地,而不会存入数据库服务器中。


      当建立好存储过程时,可以新建查询执行“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语句执行,需要多次连接数据库,或者需要对多张表进行处理时,可以将这些操作封装在一起,即创建存储过程,以后每次需要的时候直接调用执行,即可执行所有的操作,避免了多次打开、关闭数据库连接。


      ★ 当涉及到比较复杂的需求时(比如机房收费系统中的下机结算消费金额就可以采用存储过程),比如排序、计算等等,可以把数据直接传到存储过程,一系列操作在数据库服务器里进行,减小了客户端与服务器之间的数据流量,同时还保证了系统的安全性。


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


相关文章
|
7月前
|
开发框架 前端开发 .NET
七天.NET 8操作SQLite入门到实战 - (1)第七天BootstrapBlazor UI组件库引入
七天.NET 8操作SQLite入门到实战 - (1)第七天BootstrapBlazor UI组件库引入
|
7月前
|
开发框架 JSON JavaScript
ASP.NET Core3.1实战教程---基于Jquery单文件上传
ASP.NET Core3.1实战教程---基于Jquery单文件上传
82 0
|
17天前
|
消息中间件 开发框架 .NET
.NET 8 强大功能 IHostedService 与 BackgroundService 实战
【11月更文挑战第7天】本文介绍了 ASP.NET Core 中的 `IHostedService` 和 `BackgroundService` 接口及其用途。`IHostedService` 定义了 `StartAsync` 和 `StopAsync` 方法,用于在应用启动和停止时执行异步操作,适用于资源初始化和清理等任务。`BackgroundService` 是 `IHostedService` 的抽象实现,简化了后台任务的编写,通过 `ExecuteAsync` 方法实现长时间运行的任务逻辑。文章还提供了创建和注册这两个服务的实战步骤,帮助开发者在实际项目中应用这些功能。
|
2月前
|
开发框架 NoSQL MongoDB
C#/.NET/.NET Core开发实战教程集合
C#/.NET/.NET Core开发实战教程集合
|
7月前
|
开发框架 .NET 中间件
七天.NET 8操作SQLite入门到实战 - (2)第七天Blazor班级管理页面编写和接口对接
七天.NET 8操作SQLite入门到实战 - (2)第七天Blazor班级管理页面编写和接口对接
149 7
|
3月前
|
SQL 关系型数据库 数据库
七天.NET 8操作SQLite入门到实战详细教程(选型、开发、发布、部署)
七天.NET 8操作SQLite入门到实战详细教程(选型、开发、发布、部署)
|
4月前
|
测试技术 API 开发者
.NET单元测试框架大比拼:MSTest、xUnit与NUnit的实战较量与选择指南
【8月更文挑战第28天】单元测试是软件开发中不可或缺的一环,它能够确保代码的质量和稳定性。在.NET生态系统中,MSTest、xUnit和NUnit是最为流行的单元测试框架。本文将对这三种测试框架进行全面解析,并通过示例代码展示它们的基本用法和特点。
320 8
|
4月前
|
开发框架 缓存 前端开发
实战.NET Framework 迁移到 .NET 5/6
从.NET Framework 迁移到.NET 5/6 是一次重要的技术革新,涵盖开发环境与应用架构的全面升级。本文通过具体案例详细解析迁移流程,包括评估现有应用、利用.NET Portability Analyzer 工具识别可移植代码、创建新项目、逐步迁移代码及处理依赖项更新等关键步骤。特别关注命名空间调整、JSON 序列化工具更换及数据库访问层重构等内容,旨在帮助开发者掌握最佳实践,确保迁移过程平稳高效,同时提升应用性能与可维护性。
134 2
|
4月前
|
存储 NoSQL JavaScript
MongoDB存储过程实战:聚合框架、脚本、最佳实践,一文全掌握!
【8月更文挑战第24天】MongoDB是一款备受欢迎的文档型NoSQL数据库,以灵活的数据模型和强大功能著称。尽管其存储过程支持不如传统关系型数据库,本文深入探讨了MongoDB在此方面的最佳实践。包括利用聚合框架处理复杂业务逻辑、封装业务逻辑提高复用性、运用JavaScript脚本实现类似存储过程的功能以及考虑集成其他工具提升数据处理能力。通过示例代码展示如何创建订单处理集合并定义验证规则,虽未直接实现存储过程,但有效地演示了如何借助JavaScript脚本处理业务逻辑,为开发者提供更多实用指导。
71 2
|
4月前
|
开发框架 前端开发 .NET
七天.NET 8操作SQLite入门到实战 - (3)第七天Blazor学生管理页面编写和接口对接
七天.NET 8操作SQLite入门到实战 - (3)第七天Blazor学生管理页面编写和接口对接
下一篇
无影云桌面