在本人的 “ .NET简谈事务本质论”一文中我们从整体上了解了事务模型,在我们脑子里能有一个全局的事务处理结构,消除对数据库事务的依赖理解,重新认识事务编程模型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
insert
into
test
values
(
'222'
)
--我们在表test中插入一条记录
go
begin
transaction
tr
begin
try
begin
insert
into
test2
values
(
'111'
)
insert
into
test
values
(
'222'
)
--该行插入会导致主键冲突,也就是我们要的效果
end
commit
transaction
tr
end
try
begin
catch
print
'事务执行错误!'
print error_number()
rollback
transaction
tr
end
catch
|
例2:
这就是典型ADO.NET事务处理代码,其实和我们第一个例子中的T-SQL代码是差不多的,通过ADO.NET中的SqlConnection.BeginTransaction()获取到对底层ODBC中的数据库事务的引用,其实这里还没有真正的设计到.NET中的事务处理代码,这里只是对数据库管理系统的远程调用,通过远程处理的消息通讯进行事务处理远程化。
CommittableTransaction事务处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public
class
Test3
{
SqlConnection conn;
CommittableTransaction committran =
new
CommittableTransaction();
public
Test3()
{
conn =
new
SqlConnection(
"data source=.;Initial Catalog=DataMedicine;Integrated Security=SSPI"
);
DisplayTransactioninfo.Display(committran);
}
public
void
Add3()
{
conn.Open();
conn.EnlistTransaction(committran);
//需要将本次的连接操作视为事务性的
SqlCommand command =
new
SqlCommand();
try
{
command.Connection = conn;
command.CommandText =
"insert into test2 values(111)"
;
command.ExecuteNonQuery();
command.CommandText =
"insert into test values(222)"
;
command.ExecuteNonQuery();
committran.Commit();
}
catch
(Exception err) { committran.Rollback();
//出现出错执行回滚操作}
}
}
|
DependentTransaction跨线程事务处理
我们在编写高并发量程序时,都会用到多线程来进行处理,让主线程能有时间来处理第一线的请求,然后将请求分发到各个子线程上进行后台的处理。我们来看一幅图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public
class
Test6
{
CommittableTransaction commit =
new
CommittableTransaction();
SqlConnection conn1 =
new
SqlConnection(
"data source=.;Initial Catalog=DataMedicine;Integrated Security=SSPI"
);
public
Test6()
{
conn1.Open();
conn1.EnlistTransaction(commit);
}
public
void
Add6()
{
try
{
DisplayTransactioninfo.Display(commit);
SqlCommand command =
new
SqlCommand(
"insert into test2 values(111)"
, conn1);
command.ExecuteNonQuery();
Thread thread =
new
Thread(Test6.CommitThread);
thread.Start(commit.DependentClone(DependentCloneOption.BlockCommitUntilComplete));
commit.Commit();
}
catch
(Exception err) { commit.Rollback(); }
}
public
static
void
CommitThread(
object
co)
{
DependentTransaction commit = co
as
DependentTransaction;
SqlConnection conn2 =
new
SqlConnection(
"data source=.;Initial Catalog=DataMedicine;Integrated Security=SSPI"
);
conn2.Open();
conn2.EnlistTransaction(commit
as
DependentTransaction);
DisplayTransactioninfo.Display(commit);
SqlCommand command =
new
SqlCommand(
"insert into test values(111)"
, conn2);
try
{
command.ExecuteNonQuery();
commit.Complete();
}
catch
(Exception err) { Console.WriteLine(err); commit.Rollback(); }
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public
class
Test4
{
SqlConnection conn1 =
new
SqlConnection(
"data source=.;Initial Catalog=DataMedicine;Integrated Security=SSPI"
);
SqlConnection conn2 =
new
SqlConnection(
"data source=.;Initial Catalog=DataMedicine;Integrated Security=SSPI"
);
CommittableTransaction committran =
new
CommittableTransaction();
public
Test4()
{
DisplayTransactioninfo.Display(committran);
conn1.Open();
conn1.EnlistTransaction(committran);
conn2.Open();
conn2.EnlistTransaction(committran);
DisplayTransactioninfo.Display(committran);
}
public
void
Add4()
{
try
{
SqlCommand command1 =
new
SqlCommand(
"insert into test2 values(111)"
, conn1);
command1.ExecuteNonQuery();
SqlCommand command2 =
new
SqlCommand(
"insert into test values(222)"
, conn2);
command2.ExecuteNonQuery();
}
catch
(Exception err) { Console.WriteLine(err); committran.Rollback(); }
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//服务类1:
public
class
DistributedTransactionService1 : IDistributedTransaction
{
SqlConnection conn1 =
new
SqlConnection(
"data source=.;Initial Catalog=DataMedicine;Integrated Security=SSPI"
);
#region IDistributedTransaction
[OperationBehavior(TransactionAutoComplete =
true
, TransactionScopeRequired =
true
)]
public
void
Add()
{
conn1.Open();
SqlCommand command =
new
SqlCommand(
"insert into test2 values(111)"
, conn1);
command.ExecuteNonQuery();
DataBaseOperation.DisplayTransactioninfo.Display(System.Transactions.Transaction.Current);
}
#endregion
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//服务类2:
public
class
DistributedTransactionService2 : IDistributedTransaction
{
SqlConnection conn2 =
new
SqlConnection(
"data source=.;Initial Catalog=DataMedicine;Integrated Security=SSPI"
);
#region IDistributedTransaction
[OperationBehavior(TransactionAutoComplete =
true
, TransactionScopeRequired =
true
)]
public
void
Add()
{
conn2.Open();
SqlCommand command =
new
SqlCommand(
"insert into test values(222)"
, conn2);
try
{
DataBaseOperation.DisplayTransactioninfo.Display(System.Transactions.Transaction.Current);
command.ExecuteNonQuery();
}
catch
(Exception err) {
throw
err; }
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
contract=
"ServerConsole.Transaction.IDistributedTransaction"
>
contract=
"ServerConsole.Transaction.IDistributedTransaction"
>
|
Binding配置:
1
2
3
4
5
6
7
|
|
我们需要打开Binding的事务流传递。
客户端代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
DistributedTransactionClient.DistributedTransactionClient tranclient =
new
DistributedTransactionClient.DistributedTransactionClient();
DistributedTransaction2Client.DistributedTransactionClient tranclient2 =
new
DistributedTransaction2Client.DistributedTransactionClient();
using
(TransactionScope transcope =
new
TransactionScope())
{
try
{
Transaction.Current.TransactionCompleted +=
new
TransactionCompletedEventHandler(Current_TransactionCompleted);
tranclient.Add();
tranclient2.Add();
transcope.Complete();
}
catch
(Exception err) { Transaction.Current.Rollback(); }
}
static
void
Current_TransactionCompleted(
object
sender, TransactionEventArgs e)
{
if
(e.Transaction.TransactionInformation.Status ==
System.Transactions.TransactionStatus.Committed)
Console.WriteLine(e.Transaction.TransactionInformation.DistributedIdentifier);
}
|
客户端使用TransactionScope类来进行环境事务的设置,这样就很方便知道事务的执行范围,在TransactionScope里面我们可以通过Transaction.Current获取到当前上下文的事务对象,由于事务对象是存储在线程独立存储区里的,所以跨线程访问是没用的,通过依赖事务进行传递。[王清培版权所有,转载请给出署名]
文章到这里就讲完了,从本地事务、多资源管理器分布式事务、SOA结构的分布式事务,我们都能进行基本的掌握。上面的例子都是经过严格测试的。
转自:http://www.cnblogs.com/wangiqngpei557/archive/2011/12/22/2298500.html#