Good idea to use NOLOCK to work around a query/update scenario?
I'm pulling records out of a database, publishing their contents to a transactional MSMQ Queue, then updating the row to indicate that it has been published. The Enqueing-and-Updating is happening within a TransactionScope, which is itself inside of a DataReader-reading loop that's going through all the records. Ie: the reading is occurring outside of the TransactionScope. Something like this:
SqlConnection conn = new SqlConnection(ConnectionString);
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "GetUnpublishedEvents";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlDataReader reader = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection
| System.Data.CommandBehavior.SingleResult);
while (reader.Read())
using (TransactionScope scope = new TransactionScope())
{
string ID = reader.GetString(0);
string data = reader.GetString(1);
SqlConnection updateConn = new SqlConnection(ConnectionString);
updateConn.Open();
SqlCommand updateCommand = updateConn.CreateCommand();
updateCommand.CommandText = "SetEventAsPublished";
updateCommand.CommandType = System.Data.CommandType.StoredProcedure;
updateCommand.Parameters.Add(new SqlParameter("@ID", ID));
updateCommand.ExecuteNonQuery();
updateConn.Close();
Message msg = new Message(data);
RaiseMessageArrived(msg);
scope.Complete();
}
reader.Close();
The stored procedure SetEventAsPublished
used to fail with a Timeout exception until I modified GetUnpublishedEvents
to use NOLOCK
. My question is: is this a good idea? Was the timeout exception a hint that I should be doing this some other way?
I know that NOLOCK
is equivalent in SQL Server to READUNCOMMITTED
. I'm not too worried about reading uncommitted data in this application, though (it isn't inserted in a transaction in the first place).
Edit:
The stored procedures are both trivial. GetUnpublishedEvents
is just:
SELECT id, data
FROM eventsTable WITH (NOLOCK)
WHERE data IS NO开发者_开发问答T NULL
AND published IS NULL;
While SetEventAsPublished
is:
UPDATE eventsTable
SET published = GETDATE()
WHERE ID = @ID;
You're querying rows in a table and then updating them in the same transaction? As long as that's the only spot hitting the table (even if there's someone else putting in a new unpublished event, it shouldn't affect you)), I see no problem with doing it this way.
Basically you're doing the SQL equivalent of a ReaderWriterLock. It's optimized for reading, but can be elevated to allow a write within the same scope.
Just one comment, I think the second connection is unnecessary. This might be the cause of your timeout because it's escalating your transaction to use the DTC (two connections in a single transaction).
精彩评论