Quick (I think) question about how Entity Framework participates in a DTC Transaction.
If I create two DbContexts within the same distributed transaction, will data I save in the first context be available to subsequent queries via the second context?
In other words, within a DTC transaction: I fetch, change and save data via context1, then create context2 and query the same entities. Will the uncommitted data from context1 be available to context2?
That depends on the isolation level you're using.
If you were to enclose your DbContexts in a TransactionScope and specifiy IsolationLevel.ReadUncommitted, e.g.
var options = new TransactionOptions{ IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted };
using(var scope= new TransactionScope(TransactionScopeOption.Required, options))
{
... DbContexts here
scope.Complete();
}
Then your second query will be able to see the changes made by the first.
For other isolation levels they won't.
The default isolation level for SQL Server is Read Committed, but for TransactionScope is Serializable.
See http://www.gavindraper.co.uk/2012/02/18/sql-server-isolation-levels-by-example/ for some examples.
It appears that the second context can indeed see the changes committed by the first. We are using read committed isolation. I am essentially doing (pseudo code):
Start Distributed Transaction
Context1: Fetch data into entities
Context1: Change entities
Context1: Save entities
Context2: Fetch data into same entities as used context 1
Context2: Change entities
Context2: Save entities
Commit Distributed Transaction
When I fetch into context 2, I do indeed see the changes that were saved in context 1, even though they are not committed (via DTC).
Related
I am updating a column in a SQL table and I want to check if it was updated successfully or it was updated already and my query didn't do anything
as we get ##rowcount in SQL Server.
In my case, I want to update a column named lockForProcessing, so if it is already processing, then my query would not affect any row, it means someone else is already processing it, else I would process it.
If I understand you correctly, your problem is related to a multi threading / concurrency problem, where the same table may be updated simultaneously.
You may want to have a look at the :
Chapter 11. Transactions And Concurrency
The ISession is not threadsafe!
The entity is not stored the moment the code session.SaveOrUpdate() is executed, but typically after transaction.Commit().
stored and commited are two different things.
The entity is stored after any session.Flush(). Depending on the IsolationLevel, the entity won't be seen by other transactions.
The entity is commited after a transaction.Commit(). A commit also flushes.
Maybe all you need to do is choose the right IsolationLevel when beginning transactions and then read the table row to get the current value:
using (var transaction = session.BeginTransaction(IsolationLevel.Serializable))
{
session.Get(); // Read your row
transaction.Commit();
}
Maybe it is easier to create some locking or pipeline mechanism in your application code though. Without knowing more about who is accessing the database (other transactions, sessions, processes?) it is hard to answer more precisely.
Suppose I want to insert a new Experiment in my SQL Server database, using Entity framework 4.0:
Experiment has 1..* Tasks in it
Both Experiment and Task derive from EntityObject
Also, there is a database constraint that each Task must have exactly one "parent" Experiment linked to it
Insertion must be atomic. What I mean by atomic is that a reader on database must never be able to read an Experiment which is not fully written to database, for instance an Experiment with no Task.
All solutions I tried so far have the issue that some incomplete experiments can be read even though this lasts only a few seconds; i.e. the experiment finally gets populated with its Task quickly but not atomically.
More specifically,
my reader.exe reads in while(true) loop all experiments and dumps experiments with no tasks.
In parallel my writer.exe write ~1000 experiments, one by one, all with one task, and save them to database.
I cannot find a way to write my ReadAllExperiments and WriteOneExperiment functions so that I never read incomplete experiment.
How I am supposed to do that?
PS:
I'm a newbie to databases; I tried transactions with serializable isolation level on write, manual SQL requests for reading with UPDLOCK, etc. but did not succeed in solving this problem, so I'm stuck.
What I thought to be quite a basic and easy need might reveal to be ill-posed problem?
Issue is unit tested here:
Entity Framework Code First: SaveChanges is not atomic
The following should actually perform what you are after assuming you are not reading with READ UNCOMMITTED or similar isolation levels
using(var ctx = new MyContext())
{
var task = new Task{};
ctx.Tasks.Add(task);
ctx.Experiment.Add(new Experiment{ Task = task });
ctx.SaveChanges();
}
If you are using READ UNCOMMITTED or similar in this case the task will show up before the Experiment is added, I don't believe there should ever be a state where the Experiment can exist before the task given the constraint you have described.
2 solutions apparently solve our issues.
The database option "Is Read Commited Snapshot On"=True (By default, it's false)
The database option "Allow Snapshot isolation"=True + read done using snapshot isolation level. We tried the read using snapshot isolation before, but did not know about this db option. I still do not understand why we don't get an error when reading with disabled isolation level?
More information on http://www.codinghorror.com/blog/2008/08/deadlocked.html
or on
MSDN: http://msdn.microsoft.com/en-us/library/ms173763.aspx (search for READ_COMMITTED_SNAPSHOT)
http://msdn.microsoft.com/en-us/library/ms179599%28v=sql.105%29.aspx
Say that a method only reads data from a database and does not write to it. Is it always the case that such methods don't need to run within a transaction?
In many databases a request for reading from the database which is not in an explicit transaction implicitly creates a transaction to run the request.
In a SQL database you may want to use a transaction if you are running multiple SELECT statements and you don't want changes from other transactions to show up in one SELECT but not an earlier one. A transaction running at the SERIALIZABLE transaction isolation level will present a consistent view of the data across multiple statements.
No. If you don't read at a specific isolation level you might not get enough guarantees. For example rows might disappear or new rows might appear.
This is true even for a single statement:
select * from Tab
except select * from Tab
This query can actually return rows in case of concurrent modifications because it scans the table twice.
SQL Server: There is an easy way to get fast, nonblocking, nonlocking, consistent reads: Enable snapshot isolation and read in a snapshot transaction. AFAIK Oracle has this capability as well. Postgres too.
the purpose of transaction is to rollback or commit the operations done to a database, if u are just selecting values and making no change in the data there is no need of transaction.
I'm using Google App Engine with Java JPA.
The isolation level is Serializable inside transaction; Repeated Read outside transaction.
I search a lot of articles and everybody talks about behaviors between transactions, but no one mention about read within the same transaction.
Example :
/* data in User table with {ID=1,NAME='HANK'} */
BEGIN;
UPDATE User SET name = 'MING' WHERE ID=1;
SELECT name FROM User WHERE ID = 1;
COMMIT;
Result : Still {ID=1, NAME='HANK'}
My Questions:
Does Isolation level setting affect queries within the same transaction?
What is the rule with the same transaction?
Any queries done within the same transaction will be immediately visible to itself. In your example if you read row with ID of 1, you will see that it is updated. The difference is how other users are affected by your transaction. Depending on your isolation level the other user may:
Get blocked, the other user will wait until you commit / rollback
Read the data as it was before the transaction (snapshot isolation)
Read the data that is most up-to-date even without you committing (read uncommitted)
I'm just scratching the surface of isolation levels, there have been a lot of books written on the subject.
I am using transactionscope to ensure that data is being read to the database correctly. However, I may have a need to select some data (from another page) while the transaction is running. Would it be possible to do this? I'm very noob when it comes to databases.
I am using LinqToSQL and SQL Server 2005(dev)/2008(prod).
Yes, it is possible to still select data from a database while a transaction is running.
Data not affected by your transaction (for instance, rows in a table which are being not updated) can usually be read from other transactions. (In certain situations SQL Server will introduce a table lock that stops reads on all rows in the table but they are unusual and most often a symptom of something else going on in your query or on the server).
You need to look into Transaction Isolation Levels since these control exactly how this behaviour will work.
Here is the C# code to set the isolation level of a transaction scope.
TransactionOptions option = new TransactionOptions();
options.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required, options)
{
// Code within transaction
}
In general, depending on the transaction isolation level specified on a transaction (or any table hints like NOLOCK) you get different levels of data locking that protect the rest of your application from activity tied up in your transaction. With a transaction isolation level of READUNCOMMITTED for example, you can see the writes within that transaction as they occur. This allows for dirty reads but also prevents (most) locks on data.
The other end of the scale is an isolation level like SERIALIZABLE which ensures that your transaction activity is entirely isolated until it has comitted.
In adition to the already provided advice, I would strongly recommend you look into snapshot isolation models. There is a good discussion at Using Snapshot Isolation. Enabling Read Committed Snapshot ON on the database can aleviate a lot of contention problems because readers are no longer blocked by writers. Since default reads are performed under read commited isolation mode, this simple database option switch has immediate benefits and requires no changes in the app.
There is no free lunch, so this comes at a price, in this case the price being aditional load on tempdb, see Row Versioning Resource Usage.
If howeever you are using explict isolation levels and specially if you use the default TransactionScope Serializable mode, then you'll have to review your code to enforce the more bening ReadCommited isolation level. If you don't know what isolation level you use, it means you use ReadCommited.
Yes, by default a TransactionScope will lock the tables involved in the transaction. If you need to read while a transaction is taking place, enter another TransactionScope with TransactionOptions IsolationLevel.ReadUncommitted:
TransactionScopeOptions = new TransactionScopeOptions();
options.IsolationLevel = IsolationLevel.ReadUncommitted;
using(var scope = new TransactionScope(
TransactionScopeOption.RequiresNew,
options
) {
// read the database
}
With a LINQ-to-SQL DataContext:
// db is DataContext
db.Transaction =
db.Connection.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
Note that there is a difference between System.Transactions.IsolationLevel and System.Data.IsolationLevel. Yes, you read that correctly.