Using custom transaction actions in. NET2.0 _ Practical Tips

Source: Internet
Author: User
Tags commit prepare rollback sleep
The. NET 2.0 framework has new System.Transactions namespaces, which provide a range of interfaces and classes that make it much easier to use transactions in. NET 2.0 than ever before. There have been a lot of articles about manipulating database transactions under. NET 2.0, but here's how to design custom transaction operations.

   first, the transaction uses the foundation

Let's look at a section of code that uses transactions:

1using (TransactionScope ts= new TransactionScope ())
2{
3//Custom Actions
4 Ts.complete ();
5}

This defines a hidden transaction using a using statement. If we add a section of code to the statement block that operates on SQL Server, they will automatically join the transaction. As can be seen, the way this transaction is used is extremely convenient.

So is it possible to join our own defined transaction operations in the statement block, and the operation can be rolled back with its failure as the entire transaction block is successfully committed? Of course, the answer is yes, otherwise I will not write this essay.

   Ii. Implementing custom Transaction Operations

Based on the nature of the transaction, we can infer that this operation must have a way to implement actions such as commit and rollback. Yes, this is the IEnlistmentNotification interface in the System.Transactions namespace. Let's write one of the simplest implementations:

1class sampleenlistment1:ienlistmentnotification
2{
3 void Ienlistmentnotification.commit (Enlistment enlistment)
4 {
5 Console.WriteLine ("Submit!") ");
6 Enlistment. Done ();
7}
8
9 void Ienlistmentnotification.indoubt (Enlistment enlistment)
10 {
One throw new Exception ("The method or operation are not implemented.");
12}
13
Ienlistmentnotification.prepare void (preparingenlistment preparingenlistment)
15 {
Console.WriteLine ("Ready!") ");
Preparingenlistment.prepared ();
18}
19
void Ienlistmentnotification.rollback (Enlistment enlistment)
21 {
Console.WriteLine ("Roll Back!") ");
Enlistment. Done ();
24}
25}
26
27

Well, after the definition, you also need to register with the transaction manager and add it to the current transaction:

1using (TransactionScope ts= new TransactionScope ())
2{
3 SampleEnlistment1 myEnlistment1 = new SampleEnlistment1 ();
4 Transaction.Current.EnlistVolatile (MyEnlistment1, Enlistmentoptions.none);
5 Ts.complete ();
6}

To execute this piece of code, we can get the following output:

Get ready!
Submit!

Explain first that when the Ts.complete () method is invoked, the transaction is executed successfully. The transaction manager then looks for all the currently registered entries, that is, each implementation of IEnlistmentNotification, and then calls their Prepare methods, notifying each entry to prepare for submission, when all entries are called Prepared () Indicate that they are ready, and then call their commit method to commit in turn. If one of them does not invoke Prepared instead of calling Forcerollback, the entire transaction is rolled back, and the transaction manager calls the Rollback method of each entry again.

And if we comment out the Ts.complete () line in front of it, it's clear that the execution result will be:

Roll back!

   三、一个 Implementation of assignment custom Actions

Consider that we want to implement a transactional assignment operation. What should be done? Here is an example:

1class sampleenlistment2:ienlistmentnotification
2{
3 Public SampleEnlistment2 (assigntransactiondemo var, int newvalue)
4 {
5 _var = var;
6 _oldvalue = var.i;
7 _newvalue = newvalue;
8}
9
a private Assigntransactiondemo _var;
one private int _oldvalue;
a private int _newvalue;
13
Ienlistmentnotification.commit void (Enlistment enlistment)
15 {
_VAR.I = _newvalue;
Console.WriteLine ("Submit!") The value of I is changed to: "+ _var.i.tostring ());
Enlistment. Done ();
19}
20
void Ienlistmentnotification.indoubt (Enlistment enlistment)
22 {
throw new Exception ("The method or operation are not implemented.");
24}
25
-Void Ienlistmentnotification.prepare (PreparingEnlistment preparingenlistment)
27 {
Preparingenlistment.prepared ();
29}
30
To void Ienlistmentnotification.rollback (enlistment enlistment)
32 {
_VAR.I = _oldvalue;
Console.WriteLine ("Roll Back!") The value of I is changed to: "+ _var.i.tostring ());
Enlistment. Done ();
36}
37}
38
39class Assigntransactiondemo
40{
the public int i;
42
The public void assignintvarvalue (int newvalue)
44 {
SampleEnlistment2 MyEnlistment2 = new SampleEnlistment2 (this, newvalue);
The $ GUID guid = new GUID ("{3456789a-7654-2345-abcd-098765434567}");
Transaction.Current.EnlistDurable (GUID, MyEnlistment2, enlistmentoptions.none);
48}
49}
50
51

Then, you can use this:

1AssignTransactionDemo ATD = new Assigntransactiondemo ();
2atd.i = 0;
3using (TransactionScope scope1 = new TransactionScope ())
4{
5 ATD. Assignintvarvalue (1);
6 Console.WriteLine ("Business done!") ");
7 Scope1.complete ();
8 Console.WriteLine ("Before exiting the area, the value of I is:" + atd.i.tostring ());
9}
10thread.sleep (1000);
11console.writeline ("After the exit area, the value of I is:" + atd.i.tostring ());

Running this piece of code, we can see the following results:

Transaction Complete!
Before exiting the zone, the value of I is: 0
Submit! The value of I becomes: 1
After exiting the zone, the value of I is: 1

From the output result, the assignment operation was executed successfully. But does it feel a little strange? Let's make a discussion:

1, if the front does not have Thread.Sleep (1000) This line, then we will most likely see the last line of output, I will still be the value of 0! Why? It's easy to understand that this is the asynchronous invocation of the Commit method, as if another thread was opened. If the main thread does not wait, when the output of the transaction is most of the Commit method has not been executed, the output of course, the result will be wrong.

2, in this example, the assignment operation is actually performed in the Commit method. But in fact, in this case, we can also make an adjustment: Put the assignment operation at the end of the Assignintvarvalue method, and then remove the assignment from the Commit method. The related code changes are as follows:

1class sampleenlistment2:ienlistmentnotification
2{
3 void Ienlistmentnotification.commit (Enlistment enlistment)
4 {
5 enlistment. Done ();
6}
7//Other slightly
8}
9
10class Assigntransactiondemo
11{
the public int i;
13
public void Assignintvarvalue (int newvalue)
15 {
SampleEnlistment2 MyEnlistment2 = new SampleEnlistment2 (this, newvalue);
A GUID guid = new GUID ("{3456789a-7654-2345-abcd-098765434567}");
Transaction.Current.EnlistDurable (GUID, MyEnlistment2, enlistmentoptions.none);
i = newvalue;
Console.WriteLine ("Change before submitting!") The value of I is: "+ i.tostring ());
21}
22}
23
24

In this way, the results of the execution will change to:

Change before submitting! The value of I is: 1
Transaction Complete!
Before exiting the zone, the value of I is: 1
After exiting the zone, the value of I is: 1

3, on the basis of the previous, when the call to make the following changes to the place, so that the transaction failed:

1using (TransactionScope scope1 = new TransactionScope ())
2{
3 ATD. Assignintvarvalue (1);
4 Console.WriteLine ("Transaction failed!") ");
5//scope1.complete ();
6 Console.WriteLine ("Before exiting the area, the value of I is:" + atd.i.tostring ());
7}

The results of the execution at this time will change to:

Change before submitting! The value of I is: 1
Transaction failed!
Before exiting the zone, the value of I is: 1
Roll back! The value of I becomes: 0
After exiting the zone, the value of I is: 0

Visible, the transaction was successfully rolled back.

   Iv. Further discussion

We all have only one assignment operation, if we need to do it two times?

1using (TransactionScope scope1 = new TransactionScope ())
2{
3 ATD. Assignintvarvalue (1);
4 ATD. Assignintvarvalue (2);
5 Console.WriteLine ("Transaction failed!") ");
6//scope1.complete ();
7 Console.WriteLine ("Before exiting the area, the value of I is:" + atd.i.tostring ());
8}

What will be the results of this execution? Of course we want to roll back, the value of I can be changed back to 1 first, then back to 0. But what about the actual results?

Change before submitting! The value of I is: 1
Change before submitting! The value of I is: 2
Transaction failed!
Before exiting the zone, the value of I is: 2
Roll back! The value of I becomes: 0
Roll back! The value of I becomes: 1
After exiting the zone, the value of I is: 1

Obviously, the rollback of the transaction is not in the order we want it to be, what is the reason? An analysis of the mechanism makes it clear that the transaction manager sends a ROLLBACK command to each entry only when it emits an asynchronous call and is likely to be issued in the order of registration, so the order of the Rollback method is clearly not guaranteed.

At this point, if you make a small adjustment to the Rollback method:

1void Ienlistmentnotification.rollback (Enlistment enlistment)
2{
3 while (_var.i!= _newvalue)
4 {
5 Thread.Sleep (500);
6}
7 _var.i = _oldvalue;
8 Console.WriteLine ("Roll Back!") The value of I is changed to: "+ _oldvalue.tostring ());
9 Enlistment. Done ();
10}

Run it again, the result is right:

Change before submitting! The value of I is: 1
Change before submitting! The value of I is: 2
Transaction failed!
Before exiting the zone, the value of I is: 2
Roll back! The value of I becomes: 1
Roll back! The value of I becomes: 0

The results of the correct is not in fact the order of the call, but the Rollback method in the implementation of the first check the value of the _newvalue is consistent with the value of the current I, inconsistent words will wait for a while. During the wait process, the Rollback method of the other instance is executed, and it checks that the discovery is matched, so it rolls back to 1. The first Rollback wait and then check for a match and roll back to 0.

Of course, this method is highly undesirable in practical applications. And do not say that the order of execution still has a lot of risk, just design the way there is a big problem. So what should we do in practical applications? Here only provides the design idea, the concrete implementation code no longer lists.

In the previous example, two assignments were registered two times, which was the cause of the instability. We should consider that the two assignment is still only registered once, and at the first assignment, create an SampleEnlistment2 instance and save it in Assigntransactdemo, and SampleEnlistment2 need to record the current operation. The next time you assign a value, you still use this instance, and you can only record the action. Thus, when rolling back, it performs a rollback operation based on the reverse order of the record.

Any further? What if there are multiple Transaction that need to be assigned? At this point we can add a dictionary<transaction, Sampleenlistment2&gt in the Assigntransactiondemo class, and use the Transaction to find the appropriate entry.

This is the end of the discussion. In Microsoft's 101 examples, there is an example of using transactions for file copies. There is a more in-depth implementation. If you have not seen, recommend to study, I believe you read this essay, study it should no longer be a problem.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.