一:处理方法和示例代码
代码说明:
Test1为一个简单的数据库表,有两个字段,id为整型是非空关键字;name为字符型。已初始化记录一条(1,’1’);
先在需要在Test中插入两条记录,一个为(10,’10’);一个为(1,’10’);如果其中一个失败便回滚。由于第二条肯定会失败,所以如果事务处理成功,结果是Test1之中最后仍只有一条id为1的记录。
//数据库手动事务处理方法一:
SqlConnection myConn1 = new SqlConnection(Class1.conn1 );
myConn1.Open();
SqlTransaction myTrans1 = myConn1.BeginTransaction();
SqlCommand myComm1 = new SqlCommand("insert into test1 values(10,'10')",myConn1);
myComm1.Transaction = myTrans1;
try
{
int ret = myComm1.ExecuteNonQuery();
if(ret != 1)
throw new ApplicationException("");
myComm1.CommandText = "insert into test1 values (1,'1')";
ret = myComm1.ExecuteNonQuery();
if(ret != 1)
throw new ApplicationException("");
myTrans1.Commit();
}
catch(Exception ex)
{
myTrans1.Rollback();
}
finally
{
myConn1.Close();
}
//数据库手动事务处理方法二:
SqlConnection myConn1 = new SqlConnection(Class1.conn1 );
myConn1.Open();
SqlTransaction myTrans1 = myConn1.BeginTransaction();
SqlCommand myComm1 = new SqlCommand("insert into test1 values (10,'10')\r\ninsert into test1 values (1,'10')",myConn1);
myComm1.Transaction = myTrans1;
try
{
int ret = myComm1.ExecuteNonQuery();
if(ret != 2)
throw new Exception("");
myTrans1.Commit();
}
catch(Exception ex)
{
myTrans1.Rollback();
}
finally
{
myConn1.Close();
}
//数据库手动事务处理方法三:
SqlConnection myConn1 = new SqlConnection(Class1.conn1 );
myConn1.Open();
SqlTransaction myTrans1 = myConn1.BeginTransaction();
string sql = @"begin tran
insert into test1 values(10,'10')
if (@@rowcount <> 1)
begin
rollback tran
return
end
insert into test1 values(1,'10')
if @@rowcount <> 1
begin
rollback tran
return
end
commit tran";
SqlCommand myComm1 = new SqlCommand(sql,myConn1);
myComm1.Transaction = myTrans1;
try
{
myComm1.ExecuteNonQuery();
myTrans1.Commit();
}
catch(Exception ex)
{
myTrans1.Rollback();
}
finally
{
myConn1.Close();
}
//数据库手动事务处理方法四:
SqlConnection myConn1 = new SqlConnection(Class1.conn1 );
string sql = @"InsertProc"; //InsertProc为存储过程,代码同方法三中的SQL
SqlCommand myComm1 = new SqlCommand(sql,myConn1);
myComm1.CommandType = CommandType.StoredProcedure ;
try
{
myConn1.Open();
myComm1.ExecuteNonQuery();
}
catch(Exception ex)
{
//;
}
finally
{
myConn1.Close();
}
上述四种实现代码都可以成功完成该事务处理。
二.方法比较和分析
1. 方法1:
描述:这是较为常见的业务逻辑事务处理方法。把处理过程分为几个子过程;让这几个子过程都关联同一个事务;只要有一个子过程失败了,便回滚。全部子过程成功执行,提交事务。
特点:代码非常“逻辑化”;但数据库往返次数多,且实现与业务绑定很死。
适用:业务逻辑不能通过一条SQL语句或后台存储过程完成;或在每一个子过程执行完后必须进行客户端处理的情况等。
2. 方法二:
描述:这是偷懒的写法,不太常用。如果可以拼凑为一个SQL语句来完成事务处理,也就可以适用后台存储过程做。
特点:代码简单;但数据库一次往返次,业务更改时只修改拼凑的SQL语句。
适用:最好不用。如果是不同数据资源之间的可偶尔用,如乡音卡系统中的发卡操作:发卡时需要先在本地系统数据库中插入一条发卡交易记录;插入一条新发卡信息记录;然后在智能网数据库中修改新卡状态。三个子过程处于同一个事务中,此时可以把操作本地系统数据库中的两个操作拼凑为一个SQL语句,简化执行过程,又保证可以再第三步成功后再提交事务。
3. 方法三:
描述:这是不推荐的写法。原因同2。
特点:利用SQL脚本的事务控制;数据库一次往返,业务更改时只修改拼凑的SQL语句。
适用:最好不用。这种情况推荐适用存储过程完成。但有时候数据库存储过程太多了的时候,为了减轻数据库的负担或者是 第三方的数据库,无法在其数据库中创建存储过程的情况。
4. 方法四:
描述:这也是较为常见的写法。推荐使用。
特点:利用SQL存储过程的事务控制;数据库一次往返,业务更改时只修改后台存储过程;而不用修改代码。
适用:一般可以由后台完成的事务处理情况下都尽量用这种方法。需要注意的是如果存储过程超过一定数量,需要对存储过程的处理代码维护更改记录。