开发者

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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜