1.内部事物 需 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew)) 否则会出现“已终止事物” 的错误
TransactionScope 分布式事务的使用案例 以及简单说明
TransactionScope 是的.net Framework2.0版本中增加的一个新命名空间。他的用途是为数据库访问提供一个“轻量级”的事物。使用之前必须添加对 System.Transactions.dll 的引用。先介绍介绍几个简单的参数。
TransactionScopeOptions | 描述 |
Required | 如果已经存在一个事务,那么这个事务范围将加入已有的事务。否则,它将创建自己的事务。 |
RequiresNew | 这个事务范围将创建自己的事务。 |
Suppress | 如果处于当前活动事务范围内,那么这个事务范围既不会加入氛围事务 (ambient transaction),也不会创建自己的事务。当部分代码需要留在事务外部时,可以使用该选项。 |
您可以在代码的任何位置上随是查看是否存在事务范围,具体方法就是查看 System.Transactions.Transaction.Current 属性。如果这个属性为“null”,说明不存在当前事务。
若要更改 TransactionScope 类的默认设置,您可以创建一个 TransactionOptions 对象,然后通过它在
TransactionScope 对象上设置隔离级别和事务的超时时间。TransactionOptions 类有一个
IsolationLevel 属性,通过这个属性可以更改隔离级别,例如从默认的可序列化 (Serializable)
改为ReadCommitted,甚至可以改为 SQL Server 2005 引入的新的快照 (Snapshot)
级别。(请记住,隔离级别仅仅是一个建议。大多数数据库引擎会试着使用建议的隔离级别,但也可能选择其他级别。)此
外,TransactionOptions 类还有一个 TimeOut 属性,这个属性可以用来更改超时时间(默认设置为 1 分钟)。
TransactionOptions opt= new TransactionOptions();
//设置TransactionOptions
opt.IsolationLevel = IsolationLevel.ReadCommitted;
// 设置超时间隔为2分钟,默认为60秒
opt.Timeout = new TimeSpan(0, 2, 0);
使用时候将
using (TransactionScope sCope = new TransactionScope(TransactionScopeOption.RequiresNew, opt))
其他和默认一样
下面做一个简单的demo 只需要添加很少的几行代码,这个模型可以对异常进行处理,执行结束后会自行清理,此外,它还可以对命令的提交或回滚进行管理
1.TransactionScope 在一个事务范围内
在app.config中
<connectionStrings>
<add name="myCon" connectionString="Data Source=.;uid=sa;pwd=sa;database=B2C3;Asynchronous Processing=true"/>
<add name="myCon2" connectionString="Data Source=.;uid=sa;pwd=sa;database=b2c;Asynchronous Processing=true"/>
<add name="myCon3" connectionString="Data Source=.;uid=sa;pwd=sa;database=demo;Asynchronous Processing=true"/>
<add name="myCon4" connectionString="Data Source=.;uid=sa;pwd=sa;database=News;Asynchronous Processing=true"/>
</connectionStrings>
static void Main(string[] args)
{
string constr = ConfigurationManager.ConnectionStrings["myCon"].ConnectionString;
string constr2 = ConfigurationManager.ConnectionStrings["myCon2"].ConnectionString;
string sql = "insert into [Tuser](username,pwd,age) values('新闻socpe测试','bbb',10)";
#region 不同库的事务
using (TransactionScope sope = new TransactionScope())
{
using(SqlConnection con =new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(sql, con))
{
con.Open();
int a= cmd.ExecuteNonQuery();
Console.WriteLine(a);
}
}
using (SqlConnection con = new SqlConnection(constr2))
{
using (SqlCommand cmd = new SqlCommand(sql, con))
{
con.Open();
int b = cmd.ExecuteNonQuery();
Console.WriteLine(b);
}
}
addOtherUser();
sope.Complete();
}
#endregion
sope.Complete(); 是个标示。只有全部运行才提交事务
2.嵌套 调用事务
static void Main(string[] args)
{
string constr = ConfigurationManager.ConnectionStrings["myCon"].ConnectionString;
string constr2 = ConfigurationManager.ConnectionStrings["myCon2"].ConnectionString;
string sql = "insert into [Tuser](username,pwd,age) values('新闻socpe测试','bbb',10)";
#region 不同库的事务
using (TransactionScope sope = new TransactionScope(TransactionScopeOption.Required))
{
using(SqlConnection con =new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(sql, con))
{
con.Open();
int a= cmd.ExecuteNonQuery();
Console.WriteLine(a);
}
}
using (SqlConnection con = new SqlConnection(constr2))
{
using (SqlCommand cmd = new SqlCommand(sql, con))
{
con.Open();
int b = cmd.ExecuteNonQuery();
Console.WriteLine(b);
}
}
addOtherUser();
sope.Complete();
}
#endregion
}
private static void addOtherUser()
{
string constr3 = ConfigurationManager.ConnectionStrings["myCon3"].ConnectionString;
string constr4 = ConfigurationManager.ConnectionStrings["myCon4"].ConnectionString;
string sql1 = "insert into [hr_user](username,password) values('新闻socpe测试','bbb')";
string sql2 = "insert into [Users](username,userpwd) values('新闻socpe测试','bbb')";
//RequiresNew 这个事务范围将创建自己的事务。
using(TransactionScope sope=new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (SqlConnection con = new SqlConnection(constr3))
{
using (SqlCommand cmd = new SqlCommand(sql1, con))
{
con.Open();
int a = cmd.ExecuteNonQuery();
Console.WriteLine(a);
}
}
using (SqlConnection con = new SqlConnection(constr4))
{
using (SqlCommand cmd = new SqlCommand(sql2, con))
{
con.Open();
int b = cmd.ExecuteNonQuery();
Console.WriteLine(b);
}
}
sope.Complete();
}
}
总结:
现在知道了TransactionScope中的数据库操作实际是参与了其中的环境事务,将它理解为是自动建立的SqlTransaction,而嵌套在其中的TransactionScope中的数据库操作会添加到这个环境事务中(以TransactionScopeOption.Required为参数生成的TransactionScope)。
也知道了Complete方法并不是执行后,就会提交事务,而只是表明之前的动作都符合要求,只是一种确认,不执行该方法,事务便不能完成。而 只有最外层TransactionScope执行了Complete方法后,在离开using块时,事务才真正的提交。所以说 TransactionScope是能嵌套的。
Transaction类有一静态属性Current,在一个TransactionScope中的Complete方法执行之前可以访问,它返回的便是环境事务。
但是: 进入和退出事务都要快,这一点非常重要,因为事务会锁定宝贵的资源。最佳实践要求我们在需要使用事务之前再去创建它,在需要对其执行命令前迅速打开连接, 执行动作查询 (Action Query),并尽可能快地完成和释放事务。在事务执行期间,您还应该避免执行任何不必要的、与数据库无关的代码,这能够防止资源被毫无疑义地锁定过长的 时间
}