Tale from inside TransactionScope

综合编程 2017-04-05

One of the last things you want to get from your Commerce site is that the order data is gone. What can be more confused than if your log shows that the cart has been converted into a purchase order, you even got the PO number, but after that, the order disappears? It’s nowhere to be found, even if you look into database. It’s kind of magic, but not the kind of magic you would want to have.

But everything happens for a reason. And actually it’s with a good reason: data consistency.

Episerver Commerce has the concept of TransactionScope. Simply put, it allows two or more database operations to be done as atomic: Either all of them succeed, or all of them will revert back. If a TransactionScope contains 3 operations A, B, C, then even if A, B succeeded, but C is yet to commit, and something goes wrong, then A and B would be reverted.

Here’s an example of TransactionScope:

            using (var scope = new Mediachase.Data.Provider.TransactionScope())
                OrderGroupWorkflowManager.RunWorkflow(Cart, OrderGroupWorkflowManager.CartCheckOutWorkflowName, true, dic);
                Cart.CustomerId = PrincipalInfo.CurrentPrincipal.GetContactId();
                var po = Cart.SaveAsPurchaseOrder();
                // Add note to purchaseOrder
                AddNoteToPurchaseOrder("New order placed by {0} in {1}", po, PrincipalInfo.CurrentPrincipal.Identity.Name, "Public site");
                // Remove old cart
                // Commit changes

Here we are having three actions: saving a cart as a purchase order, add a note to the PO and save it again, then delete the cart. Until scope.Complete() is reached, all those changes are subjected to be reverted back. If AddNoteToPurchaseOrder fails and an exception is thrown, the first action will be reverted back. If Cart.AcceptChanges() fails, then the order and the note will be reverted back. scope.Complete() is very important, it’s like checkpoint in game – when you die before reaching a checkpoint, you’ll have to start at previous checkpoint. If something go wrong before you reach scope.Complete(), your database will what it was before the TransactionScope.

You can try to do a little experiment with TransactionScope. Put a breaking at Cart.Delete();, for example, then make sure the code stops there in the debugger. Now go to the database and try to find the newly created purchase order.

You just can’t – SQL Server tries to read, but actually it’s blocked. The level of transaction isolation of TransactionScope is Serialization, so other threads can’t read the data which are being manipulated by our thread. Of course if you write some code inside our TransactionScope to read the newly created PO, it should be fine, because it’s same thread. But other threads have to wait. Only we leave out scope.Complete(), then SQL Server Management studio can complete the read and return some data to us!

It’s worth noting that TransactionScope support nested transactions. In fact, the above example is a nested transaction. There is already a TransactionScope inside Cart.SaveAsPurchaseOrder(). In case of nested transactions, the outer most transaction wins – only when it commits then all nested transactions commits.

TransactionScope is a great feature – some data is just so important that it better be consistent other than in faulty state. One of the places where you should use TransactionScope is like above – where you do the final steps to convert a cart into an order. However, think about what would you want to put in a TransactionScope – only the critical business which should go together (or revert together). As we mentioned about, TransactionScope will block other threads from doing certain things, so too big scopes can definitely hurt your performance.

The problem I mentioned in the beginning of this blogpost was actually caused by two reasons: the unawareness of TransactionScope and its behaviors, and the lack of proper logging when an exception is thrown. When everything was taken into account, it’s clear and reasonable of why did it happen.

This post hopefully clears any confusion regarding TransactionScope – and the latter – it deserves a post on it own. I’ll come back to you soon.

责编内容by:Quan Mai's blog (源链)。感谢您的支持!


Display database pictures in a ListView control in... This example shows how you can display database pictures in a ListView con...
Is this a ‘new dawn’ for the data catalog? How should you store the information you need to understand the information i...
Webinar Thursday, April 19, 2018: Running MongoDB ... Please join Percona’s Senior Technical Operations Architect, Tim Vaillancourt ...
PPT下载丨2018 DAMS中国数据资产管理峰会精华回放... 云盘链接: https://pan.baidu.com/s/1AGYc84_qtvqMfD5aUKD05A 7月6日,2...
Dew Drop – June 7, 2018 (#2741) Top Links .NET Rocks! – Open Sourcing Uno with Francois Tanguay and J...