asp.net 事务的处理,dts 的设置,asp.net三种事务处理方法,三层架构,微软企业库,动软生成器生成的代码下如何使用事务
在上一篇文章中,由于我需要同时往 订单表和订单详情表插入数据(订单详情表里面的订单编号是订单表的id主键自动生成的值),由于牛腩购物网是用动软生成器,微软企业库的三层架构,在DAL层已经封装好了代码,所以我用到的是 TransactionScope 来实现的事务处理。
1: dts的设置 在运行里面输入 dcomcnfg
在.NET中使用TransactionScope进行事务控制时,必须设置客户端和服务器端的MSDTC安全配置如下:否则只能在数据库服务器上可以正常使用,客户端使用会报错“事务已被隐式或显式提交,或已终止。 ”。
然后在我们的项目上,先添加引用 ,并在代码中 using System.Transactions;
最后,我贴出我的代码。
我先通过 int orderid = orderdao.Add(order); 来获取订单表自动生成的ID,并且接下来,我循环购物车,把购物车里面的商品,添加到 订单详情表里面
最后我scope.Complete(); 这样就提交了事务,由于我的事务是放在 using里面的,所以会自动释放我用到的事务,主要代码都是放在try里面的,如果报错,那么位于
using里面的 事务范围,就会回滚,不执行操作。(我刚开始没有设置DTS,也报错了,也回滚了)
//开始插入到两张表,用到事务。需要在项目上添加引用 System.Transactions ,而且还需要写 using System.Transactions; using (TransactionScope scope = new TransactionScope()) //这里有创建一个 TransactionScope 表示事务性代码,因为用到using会自动释放 { try { //如果这里报错的话,整个scope 都会自动 回滚的 int orderid = orderdao.Add(order); if (orderid > 0) { DAL.OrderdetailsDAO oddao = new DAL.OrderdetailsDAO(); foreach (Model.ShopItem item in sc.GetItemList()) { oddao.Add(new Model.Orderdetails { //这里是添加订单详情表 orderid=orderid, price=item.price, proid=item.proid, quantity=item.quantity }); } scope.Complete(); } else { Utility.Tool.alert("订单添加失败,请联系管理员", this.Page); } } catch (Exception re) { Response.Write("事务错误,具体报错信息是:"+re.Message); Response.End(); } }
知识点: asp.net三种事务处理
三层结构下,数据访问层与业务逻辑分离。从对象关系角度看,业务逻辑层的对象依赖于数据访问层。.net平台提供了ado.net对数据库进行操作,connection对象提供了对database连接与transaction的功能。在分层结构下,数据访问层处理了对数据库的操作,实现了domain每一个对象与database的方法。例如对象Customer,提供CustomerDAO.Add(),CustomerDAO.Update()等等的方法,每一个方法都会引用独立的connection对象。业务层直接调用CustomerDAO的方法。connection对象对业务层是close状态,业务层不能访问到并且控制ado.net提供的transaction。在不破坏分层体系结构前提下一般有三种方式来实现。
SQL事务处理、ADO.NET事务处理、COM+事务处理(也就是文章开头的 TransactionScope )
SQL事务处理: SqlTransaction
应用程序通过在 SqlConnection 对象上调用 BeginTransaction 来创建 SqlTransaction 对象。对 SqlTransaction 对象执行与该事务关联的所有后续操作(例如提交或中止该事务)。
你可以写在sql里面,例如你写一个存储过程,在插入订单表的时候,也同时插入订单详情表
SQL 脚本使用 BEGIN TRANSACTION、COMMIT TRANSACTION、COMMIT WORK、ROLLBACK TRANSACTION 或 ROLLBACK WORK Transact-SQL 语句定义显式事务。
- BEGIN TRANSACTION
-
标记显式连接事务的起始点。
- COMMIT TRANSACTION 或 COMMIT WORK
-
如果没有遇到错误,可使用该语句成功地结束事务。该事务中的所有数据修改在数据库中都将永久有效。事务占用的资源将被释放。
- ROLLBACK TRANSACTION 或 ROLLBACK WORK
-
用来清除遇到错误的事务。该事务修改的所有数据都返回到事务开始时的状态。事务占用的资源将被释放。
ADO.NET事务处理:
在 ADO.NET SqlClient 托管提供程序中,对 SqlConnection 对象使用 BeginTransaction 方法可以启动一个显式事务。若要结束事务,可以对 SqlTransaction 对象调用 Commit()或 Rollback() 方法
public void ExecuteNoneSql(string p_sqlstr, params string[] p_cmdStr) { using (SqlConnection conn = new SqlConnection(p_sqlstr)) { Conn.Open(); SqlCommand cmd = new SqlCommand(); cmd.Connection = conn; SqlTransaction trans = null; trans = conn.BeginTransaction(); //初始化事务 cmd.Transaction = trans; //绑定事务 try { for (int i = 0; i < p_cmdStr.Length; i++) { cmd.CommandText = p_cmdStr[i]; cmd.CommandType = CommandType.Text; cmd.ExecuteNonQuery(); } trans.Commit(); //提交 } catch (SqlException e) { if (trans != null) trans.Rollback(); //回滚 else {//写日志} } } }
带保存点回滚示例:
using (SqlConnection conn = new SqlConnection(p_sqlstr)) { conn.Open(); SqlCommand cmd = new SqlCommand(); cmd.Connection = conn; SqlTransaction trans = conn.BeginTransaction("table"); cmd.Transaction = trans; try { cmd.CommandText = "Insert into table_name1 values(values1,values2,....)"; cmd.CommandType = CommandType.Text; cmd.ExecuteNonQuery(); cmd.CommandText = "Insert into table_name2 values(values1,values2,....)"; cmd.CommandType = CommandType.Text; cmd.ExecuteNonQuery(); trans.Save("table1"); cmd.CommandText = "Insert into table_name2 values(values1,values2,....)"; cmd.CommandType = CommandType.Text; cmd.ExecuteNonQuery(); trans.Save("table2"); trans.Commit(); } catch { try { trans.Rollback("table2") ; } catch { try{ trans.Rollback("table1") ; } catch{ trans.Rollback("table") ; } } } }
三者性能比较:
性能排名: SQL事务处理>ADO.NET事务处理>COM+事务处理(TransactionScope )
SQL事务处理只需要进行一次数据库交互,优点就是速度很快,而且所有逻辑包含在一个单独的调用中,与应用程序独立,缺点就是与数据库绑定。
ADO.NET需要2n次数据库往返,但相对而言,ADO.NET事务处理性能比SQL事务处理低很少,在一般应用程序中可以忽略。而且ADO.NET事务处理将事务处理与数据库独立,增加了程序的移植性。而且他也可以横跨多个数据库,不过他对于数据库的类型要求一致。
COM+事务处理性能最低,主要因为COM+本身的一些组件需要内存开销。但COM+可以横跨各种数据存储文件,这一点功能是前两者所无法媲美的。
另外:如果是asp的话,还可以在 OLE DB 中使用显式事务。调用 ITransactionLocal::StartTransaction 方法可启动事务。如果将 fRetaining 设置为 FALSE,通过调用 ITransaction::Commit 或ITransaction::Abort 方法结束事务时不会自动启动另一事务。
在 ADO 中,对 Connection 对象使用 BeginTrans 方法可启动隐式事务。若要结束该事务,可调用该 Connection 对象的 CommitTrans 或 RollbackTrans 方法。(这个也就是上面的asp的事务的方法)
在asp的时候,就用到过事务,但是这个事务是和一个 connection 链接对象在一起的
<% 'asp事务处理。 '测试数据库为sql server,服务器为本机,数据库名为test,表名为a,两个字段id(int)主键标识,num(int) set conn=server.CreateObject("adodb.connection") strConn="provider=sqloledb.1;persist security info=false;uid=sa;pwd=sa;Initial Catalog=test;Data Source=." conn.Open strConn '以上代码建立数据库连接 conn.BeginTrans '事务开始 strSql1="update a set num=1000 where id=24" '第一个sql语句为update。(语法正确) strSql2="insert into a(num) values('a')" '第二个sql语句为错误的sql语句 strSql3="insert into a(num) values(33333)" '第三个sql语句为正确的sql语句 call conn.execute(strSql1) call conn.execute(strSql2) call conn.execute(strSql3) if conn.Errors.Count=0 then conn.CommitTrans '如果没有conn错误,则执行事务提交 else conn.RollbackTrans '否则回滚 end if %>