事务简介
事务用于保证一组数据在进行更新操作之后的完整性,比如银行转帐,从A帐号取出转入B帐号,任意一个失败,则全部失败,事务的四大属性ACID。
在SQL Server连接上进行本地事务
将一个DBTransaction绑定在DBCommand上面即可完成
代码protected void Page_Load(object sender, EventArgs e)
{
string connStr = "server=HEAIPING-PC;uid=sa;pwd=sa;database=DemoDB";
string strSql1 = "insert into demoTb1 values('111')";
string strSql2 = "insert into demoTb2 values('222')";
try
{
using(SqlConnection conn=new SqlConnection(connStr))
{
conn.Open();
SqlTransaction tx = conn.BeginTransaction();
SqlCommand cmd = new SqlCommand(strSql1, conn);
cmd.Transaction = tx;
cmd.ExecuteNonQuery();
cmd.CommandText = strSql2;
cmd.ExecuteNonQuery();
tx.Commit();
}
}
catch
{
}
}
上面的代码如果在第二次插入的时候发生异常没有插入成功,那么事务不会提交,第一次的插入也是无效的。
T-SQL语言也提供了完成事务的能力。上面的操作可以通过T-SQL来完成begin transaction
insert into demoTb1 values('111')
insert into demoTb2 values('222')
if @@error=0
commit transaction
else
rollback transaction
return
其实在C#程序中,SqlClient数据提供程序就是利用T-SQL来实现事务功能的,(T-SQL中T即为Transaction)直接使用本地事务效率会很高的。但是该事务功能不支持分布式事务(DTC),之内在一个数据库中执行。
分布式事务协调器
微软提供一个与操作系统一起发布的TM(Transaction Manager),称为DTC(Distributed Transaction Coordinator)。
DTC并不在每个版本中都是必须安装或者可使用的部分。可以查看并启用之。我的Win7截图
如果DTC正在运行,就可以使用“事务列表”查看之,还可以使用“事务统计数据”获取统计。
System.Transactions
使用System.Transactions命名空间的类型重写上面的例子
代码protected void Page_Load(object sender, EventArgs e)
{
string connStr = "server=HEAIPING-PC;uid=sa;pwd=sa;database=DemoDB";
string strSql1 = "insert into demoTb1 values('111')";
string strSql2 = "insert into demoTb2 values('222')";
try
{
using (TransactionScope txScope = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
SqlCommand cmd = new SqlCommand(strSql1, conn);
cmd.ExecuteNonQuery();
cmd.CommandText = strSql2;
cmd.ExecuteNonQuery();
txScope.Complete();
}
}
}
catch
{
}
该例子说明,当System.Transactions.TransactionScope类型的对象存在的时候,开启的链接将会自动并且隐式地被登记于底层的事务中。
开始一个在两个数据库上工作的分布式事务。注,必须要启动DTC
protected void Page_Load(object sender, EventArgs e)
{
string connStr1 = "server=HEAIPING-PC;uid=sa;pwd=sa;database=DemoDB";
string connStr2 = "server=HEAIPING-PC;uid=sa;pwd=sa;database=DemoDB2";//另外一个数据库
string strSql1 = "delete from demoTb1";
string strSql2 = "insert into DB2Tb values('222')";
try
{
using (TransactionScope txScope = new TransactionScope())
{
//对第一个数据库的操作
using (SqlConnection conn1 = new SqlConnection(connStr1))
{
conn1.Open();
SqlCommand cmd = new SqlCommand(strSql1, conn1);
cmd.ExecuteNonQuery();
}
//对第二个数据库的操作
using (SqlConnection conn2 = new SqlConnection(connStr2))
{
conn2.Open();//此时必须开始DTC,否则会报错
SqlCommand cmd = new SqlCommand(strSql2, conn2);
cmd.ExecuteNonQuery();
}
txScope.Complete();
}
}
catch
{
}
}
在这种情况下,用到了DTC,个人感觉很慢,尤其在执行,第二个command的时候,当然如果没有开启DTC,第一个Command是完全可以执行下去的,但是到第二个Command是会报异常的(conn,open的时候)。
执行两次后DTC统计截图
对于DTC目前只是会用了,原理搞的不是很清楚,有人看到还望指点一二。