事务处理之前我的博客中有介绍的:
当然这次也还是以介绍本地事务为主。
上面的博客中只是通过简单的例子介绍事务的应用,但是在三层架构中事务应该怎样使用呢,要弄清楚这一点首先是明白事务、连接、command对象之间的关系
connection对象是数据连接,他决定你链接什么数据库,数据库在哪里
command 对象是查询执行,由他来完成查询语句或执行语句
事务呢,一个连接可以有多个事务。但一个事务只属于一个连接。连接就好像北京到上海的一条铁路,事务就是铁路上的列出,列车可以只有车头,也可以带有好多车厢,火车包括车头都是要到北京的。但是要是要不整列火车到达北京,要不都没有到达。
上面是我对事务的理解。
说说我的三层架构:
我的三层结构中融入了设计模式,其中U层对B层的操作是通过外观模式来操作的。外观模式的作用就是让B层复杂的逻辑统一到一个外观中来。
以注册新卡为例:
注册新卡需要插入学生信息和卡信息。当然是需要放在事务里的。要不都插入成功,要不都不插入。
通过以上我的解说大家应该能想出,事务的开始和结束都要放在外观层的(后面用Fa层代替)但是事务的创建时要在连接的基础上的。也就是Fa层要获得连接。就要在B、D、Factory、IDAL走一遍。然后获得的Transaction,还要以参数的形式传回D层操作。这个过程走下来,我发现自己要改的东西又有很多了。
让我们先看看怎么实现。
这里我找了一部分别人的代码。其中的Sqlhelper写的比较有代表性。给大家分享。当然方法一定不止是有一个的。大家写好的sqlhelper不一定不好。
将事务处理独立出来,该类的功能主要是创建数据库连接,开启事务处理,关闭连接。代码如下:
ImportsSystem.Data.Common
PublicClassTranUtil
PrivateSubNew()
EndSub
'开启事务
PublicSharedFunctionBeginTransaction()AsIDbTransaction
DimconnAsDbConnection=DButil.CreateConnection
Ifconn.State=ConnectionState.ClosedThen
conn.Open()
EndIf
DimtranAsIDbTransaction=conn.BeginTransaction()
Returntran
EndFunction
'关闭连接
PublicSharedSubClose(ByValtranAsIDbTransaction)
IftranIsNotNothingAndAlsotran.Connection.State=ConnectionState.OpenThen
tran.Connection.Close()
tran=Nothing
EndIf
EndSub
数据库操作类代码如下:
ImportsSystem.Data.Common
ImportsSystem.Configuration
ImportsSystem.Reflection.MethodBase
ImportsMySql.Data.MySqlClient
Importslog4net
PublicClassDButil
PrivateSharedlogAsILog=LogManager.GetLogger(GetCurrentMethod().DeclaringType.ToString)
PrivateSubNew()
EndSub
'创建数据库链接
PublicSharedFunctionCreateConnection()AsDbConnection
log.Info("创建数据库连接")
Try
'读取app.config中的连接字符串
DimsConnAsString=ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString
'创建数据库连接
DimdbConnAsMySqlConnection=NewMySqlConnection(sConn)
ReturndbConn
CatchexAsException
log.Error(ex)
Throwex
EndTry
EndFunction
'取得DbCommand
PublicSharedFunctionGetSqlCommand(ByValconnectionAsDbConnection,ByValsqlQueryAsString)AsDbCommand
log.Info("sqlQuery:"&sqlQuery)
Try
DimdbCommandAsMySqlCommand=connection.CreateCommand
dbCommand.CommandText=sqlQuery
dbCommand.CommandType=CommandType.Text
ReturndbCommand
CatchexAsException
log.Error(ex)
Throwex
EndTry
EndFunction
'给DbCommand对象的参数赋值
PublicOverloadsSharedSubAddParameter(ByValcmdAsDbCommand,ByValparameterNameAsString,ByValvalueAsObject)
log.Info("parameterName="¶meterName&",value="&value)
DimdbParameterAsDbParameter=cmd.CreateParameter()
dbParameter.ParameterName=parameterName
dbParameter.Value=value
dbParameter.Direction=ParameterDirection.Input
cmd.Parameters.Add(dbParameter)
EndSub
#Region"事务处理"
'返回单个值,如:单个字段的值或者Count(*)的值,具有事务处理功能
PublicSharedFunctionExecuteTranScalar(ByValconnAsDbConnection,ByValcmdAsDbCommand)AsObject
Try
Ifconn.State=ConnectionState.ClosedThen
conn.Open()
EndIf
DimobjAsObject=cmd.ExecuteScalar
log.Info("ExecuteScalarResult:"&obj)
Returnobj
CatchexAsException
log.Error(ex)
Throwex
EndTry
EndFunction
'新增,删除,修改,具有事务处理功能
PublicSharedFunctionExecuteTranNonQuery(ByValconnAsDbConnection,ByValcmdAsDbCommand)AsInteger
Try
Ifconn.State=ConnectionState.ClosedThen
conn.Open()
EndIf
DimiAsObject=cmd.ExecuteNonQuery
log.Info("ExecuteNonQueryResult:"&i)
Returni
CatchexAsException
log.Error(ex)
Throwex
EndTry
EndFunction
#EndRegion
EndClass
在DBUtil中,所有具有事务处理的方法都不需要关闭连接,数据库的连接在其开启的地方进行关闭。
在DAL层中,接收来自BLL层的connection,然后调用DBUtil中的方法进行数据的操作。代码如下:
主档
PublicFunctionInsertOutStockMain(ByValtranAsIDbTransaction,ByValarl()AsString)AsInteger
DimsbSqlAsNewStringBuilder
sbSql.Append("insertintooutstockmain(stock_no,stock_date,stock_person,buyer_id)")
sbSql.Append("values(?stock_no,?stock_date,?stock_person,?buyer_id)")
Try
DimmyCmdAsMySqlCommand=DButil.GetSqlCommand(tran.Connection,sbSql.ToString)
DButil.AddParameter(myCmd,"?stock_no",arl(0))
DButil.AddParameter(myCmd,"?stock_date",arl(1))
DButil.AddParameter(myCmd,"?stock_person",arl(2))
DButil.AddParameter(myCmd,"?buyer_id",arl(3))
DimiResultAsInteger=DButil.ExecuteTranNonQuery(tran.Connection,myCmd)
ReturniResult
CatchexAsException
Throwex
EndTry
EndFunction
'明细档
PrivateFunctionInsertOutStockDtl(ByValtranAsIDbTransaction,ByValdrAsDataRow)AsInteger
DimsbSqlAsNewStringBuilder
sbSql.Append("insertintooutstock(seq_no,stock_no,quatity,in_price,out_price)")
sbSql.Append("values(?seq_no,?stock_no,?quatity,?in_price,?out_price)")
DimiResultAsInteger=0
Try
DimmyCmdAsMySqlCommand=DButil.GetSqlCommand(tran.Connection,sbSql.ToString)
DButil.AddParameter(myCmd,"?seq_no",dr.Item("seq_no"))
DButil.AddParameter(myCmd,"?stock_no",dr.Item("stock_no"))
DButil.AddParameter(myCmd,"?quatity",dr.Item("quatity"))
DButil.AddParameter(myCmd,"?in_price",dr.Item("in_price"))
DButil.AddParameter(myCmd,"?out_price",dr.Item("out_price"))
iResult=DButil.ExecuteTranNonQuery(tran.Connection,myCmd)
ReturniResult
CatchexAsException
Throwex
EndTry
EndFunction
连接的创建,及事务的开启均在 BLL 层进行,执行完毕后,连接也在该层关闭。代码如下:
PublicFunctionInsertOut(ByValarl()AsString,ByValdtAsDataTable)AsInteger
DimiResultAsInteger=0
UsingtranAsIDbTransaction=TranUtil.BeginTransaction
Try
iResult=InsertOutStockMain1(tran,arl)
IfiResult=0Then
ThrowNewBaseException("新增出货主档失败!")
EndIf
iResult=0
ForEachdrAsDataRowIndt.Rows
iResult+=InsertOutStockDtl(tran,dr)
Next
tran.Commit()
ReturniResult
CatchexAsException
IftranIsNotNothingThen
tran.Rollback()
EndIf
Throwex
Finally
TranUtil.Close(tran)
EndTry
EndUsing
EndFunction
说明:实例代码连接的是MySql数据库
其中他的DButil 也就是我说的sqlhelper
但是这种方法我也说过需要把Transaction作为参数一层层往下传的。有没有更好的办法呢。一定使用的。方法我们下一篇博客介绍。