引言:
做机房收费系统时,有研究过在三层架构中添加事务处理的机制。那时候基本是自创的一个方法。因为要访问一个公共的静态变量。当时自然就想到了使用实体类,这样得到公共的Connection以后就可以不用在每个层中传了。同样这次的系统中也用到了事务机制的处理。发现了另一种使用事务机制的好的方法,当然也要拿出来给大家分享下了。
基本思路:
看代码之前,大概说一下这次系统中使用是如何使用事务机制了。事务无非就是同时执行多条sql语句,要保证事务的实现无非就是让执行这几条sql语句在同一个Connection链接下操作。其实事务很简单,不过是和三层混在了一起所以让人无从下手罢了,这次的系统中实现事务机制的方法是把要同时执行的多条sql语句放在D层的一个方法里。如果多条sql语句都没有参数,那么就只需要把这多条的sql语句保存起来然后再传给sqlhelper逐条的执行,如果多条的sql语句都带有参数,那么需要保存的就不止有sql语句还用其对应的参数了。
技术难点:
看到这里大家发现其实主要的技术难点只剩下两个,
1.保存这些sql语句,以及他们可能有的参数,然后对应的取出来。
2.就是把对应的把sql语句自己的参数附加上去。
代码以及说明:
说到现在我想应该让大家看看代码了:(这里的例子是带有参数的sql语句,这个掌握了,不带参数的自然也就掌握了。)
首先是D层确定需要放在同一个事务中处理的sql语句,并保存起来用于送给sqlhelper处理。
''' <summary>
''' 注册卡号时的事务,需要向学生表,卡表,充值记录中添加信息--韩义
''' </summary>
''' <param name="enStuCard">附有所有信息的学生卡实体</param>
''' <param name="enRecharge">附有所有信息的充值实体</param>
''' <returns>bool,true则表示成功,false则表示失败</returns>
''' <remarks></remarks>
Public Function Register(ByVal enStuCard As Entity.StuCardEntity, ByVal enRecharge As Entity.ChargeEntity) As Boolean Implements IDAL.IAffairsDAL.Register
Dim HashList As New Hashtable '定义hashtable。
'第一条需要执行的sql语句,以及他的参数。
Dim sql1 As String = "insert into T_Card(CardNo,StudentNo,Cash,CardType,Creater,Status,IsCheck,Date,Time) values(@CardNo,@StudentNo,@Cash,@CardType,@Creater,@Status,@IsCheck,@Date,@Time)"
Dim sqlParam1(8) As SqlParameter
sqlParam1(0) = SqlHelperDAL.AddSqlParameter("@CardNo", SqlDbType.Char, enStuCard.CardNO)
sqlParam1(1) = SqlHelperDAL.AddSqlParameter("@StudentNo", SqlDbType.Char, enStuCard.StudentNO)
sqlParam1(2) = SqlHelperDAL.AddSqlParameter("@Cash", SqlDbType.Decimal, CDec(enStuCard.Cash))
sqlParam1(3) = SqlHelperDAL.AddSqlParameter("@CardType", SqlDbType.VarChar, enStuCard.CardType)
sqlParam1(4) = SqlHelperDAL.AddSqlParameter("@Creater", SqlDbType.Char, enStuCard.Creater)
sqlParam1(5) = SqlHelperDAL.AddSqlParameter("@Status", SqlDbType.Char, enStuCard.Status)
sqlParam1(6) = SqlHelperDAL.AddSqlParameter("@IsCheck", SqlDbType.Char, enStuCard.IsCheck)
sqlParam1(7) = SqlHelperDAL.AddSqlParameter("@Date", SqlDbType.Char, enStuCard.RegisterDate)
sqlParam1(8) = SqlHelperDAL.AddSqlParameter("@Time", SqlDbType.Char, enStuCard.RegisterTime)
'第二条需要执行的语句,以及他的参数
Dim sql2 As String = "insert into T_Student(StudentNo,StudentName,Sex,Department,Grade,Class) values(@StudentNo,@StudentName,@Sex,@Department,@Grade,@Class)"
Dim sqlParam2(5) As SqlParameter
sqlParam2(0) = SqlHelperDAL.AddSqlParameter("@StudentNo", SqlDbType.Char, enStuCard.StudentNO)
sqlParam2(1) = SqlHelperDAL.AddSqlParameter("@StudentName", SqlDbType.Char, enStuCard.StudentName)
sqlParam2(2) = SqlHelperDAL.AddSqlParameter("@Sex", SqlDbType.Char, enStuCard.Sex)
sqlParam2(3) = SqlHelperDAL.AddSqlParameter("@Department", SqlDbType.VarChar, enStuCard.Department)
sqlParam2(4) = SqlHelperDAL.AddSqlParameter("@Grade", SqlDbType.Char, enStuCard.Grade)
sqlParam2(5) = SqlHelperDAL.AddSqlParameter("@Class", SqlDbType.Char, enStuCard.ClassName)
'第三条需要执行的语句以及他的参数
Dim sql3 As String = "insert into T_Recharge(CardNo,AddMoney,UserID,IsCheck,Date,Time) values(@CardNo,@AddMoney,@UserID,@IsCheck,@Date,@Time)"
Dim sqlParam3(5) As SqlParameter
sqlParam3(0) = SqlHelperDAL.AddSqlParameter("@CardNo", SqlDbType.Char, enRecharge.CardNO)
sqlParam3(1) = SqlHelperDAL.AddSqlParameter("@AddMoney", SqlDbType.Decimal, CDec(enRecharge.AddMoney))
sqlParam3(2) = SqlHelperDAL.AddSqlParameter("@UserID", SqlDbType.Char, enRecharge.UserID)
sqlParam3(3) = SqlHelperDAL.AddSqlParameter("@IsCheck", SqlDbType.Char, enRecharge.IsCheck)
sqlParam3(4) = SqlHelperDAL.AddSqlParameter("@Date", SqlDbType.Char, enRecharge.ChargeDate)
sqlParam3(5) = SqlHelperDAL.AddSqlParameter("@Time", SqlDbType.Char, enRecharge.Time)
'把三条sql语句和对应的参数保存到hashtable中
HashList.Add(sql1, sqlParam1)
HashList.Add(sql2, sqlParam2)
HashList.Add(sql3, sqlParam3)
Try
'传递个sqlhelper执行
SqlHelperDAL.ExecuteSqlTran(HashList)
Return True
Catch ex As Exception
Return False
End Try
End Function
''' <summary>
''' 执行多条sql语句,实现数据库事务--韩义
''' </summary>
''' <param name="SQLStringList">sql语句的哈希表</param>
''' <remarks></remarks>
Public Sub ExecuteSqlTran(ByVal SQLStringList As Hashtable)
Using (conn) '打开数据库连接
'打开数据库连接
conn.Open() '打开数据连接
Dim trans As SqlTransaction = conn.BeginTransaction() '开始数据库事务
Using (trans)
Try
'循环
For Each myDE As DictionaryEntry In SQLStringList
Dim cmdText As String = myDE.Key.ToString()
Dim cmdParms() As SqlParameter = CType((myDE.Value), SqlParameter())
PrepareCommand(cmd, conn, trans, cmdText, cmdParms)
Dim val As Integer = cmd.ExecuteNonQuery() '调用ExecuteNonQuery函数,返回受影响的行数
cmd.Parameters.Clear() '清空参数对象
Next
trans.Commit() '提交事务
Catch ex As Exception
trans.Rollback() '事务回滚
Throw
End Try
End Using
End Using
End Sub
''' <summary>
''' 写入参数--韩义
''' </summary>
''' <param name="cmd">sqlCommand命令</param>
''' <param name="conn">sqlconnection命令</param>
''' <param name="trans">事务</param>
''' <param name="cmdText">sql语句</param>
''' <param name="cmdParms">参数</param>
''' <remarks></remarks>
Public Sub PrepareCommand(ByVal cmd As SqlCommand, ByVal conn As SqlConnection, ByVal trans As SqlTransaction, ByVal cmdText As String, ByVal cmdParms() As SqlParameter)
If conn.State <> ConnectionState.Open Then
conn.Open()
End If
cmd.Connection = conn '设置连接
cmd.CommandText = cmdText '设置对数源执行的sql语句
If Not IsNothing(trans) Then
cmd.Transaction = trans '设置执行事务
cmd.CommandType = CommandType.Text
End If
If Not IsNothing(cmdParms) Then '如果存在参数
'遍历每个参数
For Each parameter As SqlParameter In cmdParms
If (parameter.Direction = ParameterDirection.InputOutput Or parameter.Direction = ParameterDirection.Input) And (IsDBNull(parameter.Value)) Then
parameter.Value = DBNull.Value '附空值
End If
cmd.Parameters.Add(parameter) '加入参数
Next
End If
End Sub