I am trying to use a DocumentDb write as a part of a transaction like below -
using (var scope = new TransactionScope)
{
//first transaction
//write to document db
//third transaction
}
I observed that if the third transaction fails, documentDb write is not rolled back and I still see the document in the collection. The first transaction (NEventStore in this case) rolls back perfectly. Does anyone know if DocumentDb supports TrnasactionScope. What if I have a nested transaction?
Thanks!
Edit:
So looks like TransactionScope is not supported with DocumentDb and it knows nothing about them. Is there a way to make DocumentDb transactions part of an external transaction from C#? Has anyone come across this use case before?
Edit 2: Follow-up question and answer here as suggested
DocumentDB operations are independent from TransactionScope. Once an operation returns, it's done. The database service doesn't know anything about TransactionScope and isn't connected to it in any way.
DocumentDB does have a transaction scope of its own, when working with server-side stored procedures. You can have multiple database calls within the stored proc, and if everything is successful, there's an implicit commit upon the stored procedure exiting. If something goes wrong and an exception is thrown, an implicit rollback is executed for all operations performed to the database within the stored procedure's scope.
Lots of SQL users don't understand what to do where transactions are not available.
You should implement compensation logic your own or use frameworks like Windows Workflow Foundation. Compensation logic is related to Enterprise Integration Patterns. You also may use correlation ID pattern to check if big operation was done.
SQL people manage big operations in the same way when it is necessary to make long running transaction.
https://www.amazon.com/Enterprise-Integration-Patterns-Designing-Deploying/dp/0321200683/ref=sr_1_1?ie=UTF8&qid=1480917322&sr=8-1&keywords=integration+patterns
Related
Morning all,
I am working on a project where I am saving data to Mongo DB and also to Sql Server (Entity Framework code first). There are a number of scenarios where I carry out a write to each database in a single block of code. I'm wondering, can any of you suggest a way to handle this in something similar to a transaction ? such that if any part of the code block fails, the whole thing should fail and rollback ?
I don't think there's any bullet-proof way of doing this since you not only have two separate connections but also two different architectures.
Assuming your SQL Server has the more complicated data model (the one that's more likely to fail for some reason) I came up with an approach in the past that worked for me:
Execute the operations sequentially not both at the same time
Execute the SQL satement first, if it fails don't execute the MongoDB statement and you'll be consistent
Should it succeed, execute the MongoDB statement next
If the MongoDB statement fails write an error log. Make sure the log is not on a remote machine so that the possibility that the logging could fail is as small as possible.
You can later use the error log to either manually or automatically salvage your data. In any case you should implement a retry policy for all statements, since the most likely reason for a failed operation is (given your code is correct) a timing issue and retrying solves this in general. If you're doing it right there will be maybe like one exotic error a month.
Of course in step 4 you could try to revert the SQL operation, instead of (or in addition to) writing a log entry. But this is mostly cumbersome and leaves you with the question what to do should the revert fail.
Maybe there still is some magic middleware to integrate MongoDB statements into an SQL transaction but for the time being I would just acknowledge that data consistency and using different databases are opposing goals. Try to monitor errors closely and reduce the error potential.
Two Phase Commit will suit your scenario. In a single transaction we can hit any number(normally we use two) of DB's and maintain our Data synchronized across the DB's.
More info on Two Phase Commit
https://lostechies.com/jimmybogard/2013/05/09/ditching-two-phased-commits/
https://www.coursera.org/learn/data-manipulation/lecture/mXS0H/two-phase-commit-and-consensus-protocols
https://sankarsan.wordpress.com/tag/two-phase-commit/
Read this post
How to force only one transaction within multiple DbContext classes?
I'm maintaining a ASP/C# program that uses an MS SQL Server 2008 R2 for its database requirements.
On normal and perfect days, everything works fine as it is. But we don't live in a perfect world.
An Application (for Leave, Sick Leave, Overtime, Undertime, etc.) Approval process requires up to ten separate connections to the database. The program connects to the database, passes around some relevant parameters, and uses stored procedures to do the job. Ten times.
Now, due to the structure of the entire thing, which I can not change, a dip in the connection, or heck, if I put a debug point in VS2005 and let it hang there long enough, the Application Approval Process goes incomplete. The tables are often just joined together, so a data mismatch - a missing data here, a primary key that failed to update there - would mean an entire row would be useless.
Now, I know that there is nothing I can do to prevent this - this is a connection issue, after all.
But are there ways to minimize connection lag / failure? Or a way to inform the users that something went wrong with the process? A rollback changes feature (either via program, or SQL), so that any incomplete data in the database will be undone?
Thanks.
But are there ways to minimize connection lag / failure? Or a way to
inform the users that something went wrong with the process? A
rollback changes feature (either via program, or SQL), so that any
incomplete data in the database will be undone?
As we discussed in the comments, transactions will address many of your concerns.
A transaction comprises a unit of work performed within a database
management system (or similar system) against a database, and treated
in a coherent and reliable way independent of other transactions.
Transactions in a database environment have two main purposes:
To provide reliable units of work that allow correct recovery from failures and keep a database consistent even in cases of system
failure, when execution stops (completely or partially) and many
operations upon a database remain uncompleted, with unclear status.
To provide isolation between programs accessing a database concurrently. If this isolation is not provided, the program's outcome
are possibly erroneous.
Source
Transactions in .Net
As you might expect, the database is integral to providing transaction support for database-related operations. However, creating transactions from your business tier is quite easy and allows you to use a single transaction across multiple database calls.
Quoting from my answer here:
I see several reasons to control transactions from the business tier:
Communication across data store boundaries. Transactions don't have to be against a RDBMS; they can be against a variety of entities.
The ability to rollback/commit transactions based on business logic that may not be available to the particular stored procedure you are calling.
The ability to invoke an arbitrary set of queries within a single transaction. This also eliminates the need to worry about transaction count.
Personal preference: c# has a more elegant structure for declaring transactions: a using block. By comparison, I've always found transactions inside stored procedures to be cumbersome when jumping to rollback/commit.
Transactions are most easily declared using the TransactionScope (reference) abstraction which does the hard work for you.
using( var ts = new TransactionScope() )
{
// do some work here that may or may not succeed
// if this line is reached, the transaction will commit. If an exception is
// thrown before this line is reached, the transaction will be rolled back.
ts.Complete();
}
Since you are just starting out with transactions, I'd suggest testing out a transaction from your .Net code.
Call a stored procedure that performs an INSERT.
After the INSERT, purposely have the procedure generate an error of any kind.
You can validate your implementation by seeing that the INSERT was rolled back automatically.
Transactions in the Database
Of course, you can also declare transactions inside a stored procedure (or any sort of TSQL statement). See here for more information.
If you use the same SQLConnection, or other connection types that implement IDbConnection, you can do something similar to transactionscopes but without the need to create the security risk that is a transactionscope.
In VB:
Using scope as IDbTransaction = mySqlCommand.Connection.BeginTransaction()
If blnEverythingGoesWell Then
scope.Commit()
Else
scope.Rollback()
End If
End Using
If you don't specify commit, the default is to rollback the transaction.
I have to implement Transactions in my code. I have the following options:-
TransactionScope from C# code:- I will use this case if i have some logical code in transaction along with my Database calls.Transaction rolls back and locks are released if command timeouts are there.
Having Explicit transactions in SP:- In case of command timeout, Transactions remain opens and locks are not released.
Has any one of you faced similar issues. Please suggest. Also tell me setting XACT_ABORT_ON will help in the second case.
If your stored procedure is not an "interface procedure" (called by third-party outside your code) I recommend using TransactionScope or creating SqlTransaction in code for your procedure call. Handling transactions in code is much easier. You may read this article: http://www.code-magazine.com/Article.aspx?quickid=0305111 - as you can see if you start using transactions in stored procedures things may get unnecesarily complicated.
I always use SET XACT_ABORT ON
Server side transactions don't require MSDTC and have less overhead
TRY/CATCH makes the stored procs more reliable
See my answer here for a safe stored proc template which will deal with nested transactions too: Nested stored procedures containing TRY CATCH ROLLBACK pattern?
I am running into situations in my application where I need to use table lock hints or set the transaction isolation level to something other than the default Read Committed, in order to resolve deadlock issues. I am using a service oriented architecture, with each service call operating as an atomic operation, and Linq To Sql is serving as a lightweight DAL. Each service call calls my Business Layer and declares a new transaction like this:
using (var scope = new TransactionScope())
{
// Get datacontext
// do Business Logic stuff, including database operations via Linq To Sql
// Save transaction
scope.Complete();
}
The problem is sometimes I have complicated business logic that requires many database operations. Some reads, some writes, some reads for updating, etc, all within the same service call, and thus the same transaction.
I have read about the inability of Linq To Sql to add table lock hints to your linq query, with the suggested solution of using TransactionScope isolation levels instead. That's great and all, but in my situation, where each Transaction is for the purpose of an atomic service call, I don't see where this would work. For example, if I need to read one table without locking and dirty reads may be OK, and turn around and do another read for the purpose of updating, and do an update. I don't want to set Read Uncommitted for the entire transaction, only one particular read, so what do I do?
Is there not an extension I can implement that will allow me to add table lock hints, without using views or stored procedures, or using datacontext.ExecuteQuery("my raw sql string here")
I think the best answer here is to use multiple Transactions, and batch the transactions that only read "dirty" in one batch, and the updates that require read committed in another batch. If any information needs to cross batches, setup a temporary in memory cache for that data.
We have a test that runs within a transaction scope. We dispose of the transaction scope at the end to avoid changing the database.
This works fine in most cases.
However, when we use Entity Framework to execute a stored procedure which contains a transaction, which is committed inside the stored procedure. We get the following error:
"Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction.\r\n "
Is it possible combine transaction scope with committing a transaction inside a stored procedure?
While you may or may not be able to solve this particular problem, I'd suggest that avoiding it entirely might be a better option. As you've seen, depending on a transaction to guarantee that your database is in a particular state doesn't always work. Also, because you are using multiple connections to the DB, you've automatically promoted any transactions that do occur to distributed transactions -- a subtle distinction, perhaps, but it changes the nature of the test. You may end up writing code to overcome the particular limitations of distributed transactions that wouldn't otherwise have been needed.
A better strategy would be -- for unit tests, anyway -- to mock out the database dependency, using in-memory mock or fake objects in place of the database. I've done something similar for LINQ to SQL (see my blog entry on the subject) For integration tests, I think you are better off using a test instance and writing set up code that reinitializes the state of the DB to known values before each test than introducing an extra transaction to clean things up. That way if your clean up code fails in a test, it won't affect other tests being run.
I use the following code inside an SP to handle contexts where a transaction may or may not be currently in force:-
DECLARE #InTran int
Set #InTran = ##TRANCOUNT
IF #InTran = 0 BEGIN TRANSACTION
/* Stuff happens */
IF #InTran = 0 AND ##TRANCOUNT > 0 COMMIT TRANSACTION
Only thing I'm not sure of is if ##TRANCOUNT reflects a transaction from a Transaction scope, its worth a shot though.