| Author |
Topic |
|
SamC
White Water Yakist
3467 Posts |
Posted - 2004-05-13 : 08:17:07
|
| I think I asked this question long ago and far away, but hey ...Does the following check for timestamp before INSERT need to be bracketed with begin tran or not?[CODE]BEGIN TRANIF EXISTS (SELECT * FROM dbo.ISSOS WHERE ISSOID = @ISSOID AND RowID = @RowID) BEGIN -- Timestamp Valid? UPDATE dbo.ISSOS -- Mark this row deleted SET Deleted = 1 WHERE ISSOID = @ISSOIDEND ELSE BEGIN SET @ReturnMessage = 'Row was modified by another user before delete. Try again.' SET @ReturnValue = 1ENDCOMMIT TRAN[/CODE]such that the update will appear atomic and concurrent users executing the same update will find one is the winner and the other denied?Column ISSOID is the PK and RowID is TIMESTAMP.Sam |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2004-05-13 : 12:13:19
|
| Is that part of a larger sproc?And isn't a timestamp uniqu across all tables?So what's with the PK and a timestamp?Looks like this would be a good reason for a trigger though...Brett8-) |
 |
|
|
derrickleggett
Pointy Haired Yak DBA
4184 Posts |
Posted - 2004-05-13 : 13:27:32
|
| The only reason I could see for the BEGIN TRAN etc. is if it's part of a larger proc, which is what Brett said. I don't know that I would agree with the trigger question. Wrapping this in a BEGIN and COMMIT will basically provide any locking you need, which seems to be what you're getting at. ???MeanOldDBAderrickleggett@hotmail.comWhen life gives you a lemon, fire the DBA. |
 |
|
|
SamC
White Water Yakist
3467 Posts |
Posted - 2004-05-13 : 16:40:28
|
| Since I seem to be the only one that seems to have a problem, I'm probably confused. Situation Normal.RowID is of type TIMESTAMP and is used to verify that the row to be updated hasn't been updated by another user since the row was read. There's an ASP interface in use by multiple operators, and I suppose it's possible that two operators might be updating the same row. If another user has updated the row values, RowID is automatically changed (it's a TIMESTAMP). The Update procedure checks that the value of RowID has not changed before applying the second user's updates, and returns a denial if there's no match.So what's the problem. If SQL executes multiple requests at the same time, timeslicing between different execution requests, then the IF EXISTS / UPATE must be an atomic sequence or the test is useless. I thought BEGIN TRAN / COMMIT TRAN might make it atomic.Sam |
 |
|
|
derrickleggett
Pointy Haired Yak DBA
4184 Posts |
Posted - 2004-05-13 : 22:31:47
|
| Can't you just do this?UPDATE dbo.ISSOS -- Mark this row deletedSET Deleted = 1WHERE ISSOID = @ISSOIDAND RowID = @RowIDIF @@ROWCOUNT <> 0BEGIN SET @ReturnMessage = 'Row was modified by another user before delete. Try again.' SET @ReturnValue = 1ENDMeanOldDBAderrickleggett@hotmail.comWhen life gives you a lemon, fire the DBA. |
 |
|
|
SamC
White Water Yakist
3467 Posts |
Posted - 2004-05-13 : 22:55:57
|
| Schweeeeeeeeeeet ! |
 |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-05-14 : 00:57:24
|
| Your initial post would not work and the transaction would not make any difference (apart from making the update take longer).Without a holdlock hint the shared lock taken by the select would be released immediately. Even if it wasn't two spids could take the shared lock at the same time and both pass the test.The two spids could then both perform the update - the first being overwritten by the second.For that code to work it would need something like(holdlock, tablockx) on the select to prevent the other spid performing the select until the update completes.The code derrickleggett gave should beIF @@ROWCOUNT = 0Also be careful about @@rowcount being modified by triggers (depending on version) you might want to set the @ReturnValue in the update instead.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
derrickleggett
Pointy Haired Yak DBA
4184 Posts |
Posted - 2004-05-14 : 02:13:52
|
| :) The ROWCOUNT was a dumb error on my part. If he's running SQL Server 2000, this shouldn't be an issue. The code will work. He just needs to make the @@ROWCOUNT = 0.MeanOldDBAderrickleggett@hotmail.comWhen life gives you a lemon, fire the DBA. |
 |
|
|
SamC
White Water Yakist
3467 Posts |
Posted - 2004-05-14 : 08:14:17
|
| Thanks for the feedback. So BEGIN TRAN / COMMIT TRAN doesn't do anything to make a sequence atomic, but it has other vitures I'm sure.So I'm OK using Derrick's suggestion. This problem is solved. But I'm wondering if there may be other problems down the road that might involve 2 or 3 SQL statements to work as an atomic unit. Is this not a real problem - if it is, what techniques are available to gate a few statements so user's don't stomp on each other? |
 |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-05-15 : 08:35:40
|
| Transactions will make updates atomic and prevent access to updated records - it's just selects that you need to be careful of. You will need code including some variation of:begin tranupdate tblselect @rowcount = @@rowcount, @error = @@errorif @error <> 0begin raiserror('failed',16,-1) rollback tran returnendupdate tblselect @rowcount = @@rowcount, @error = @@errorif @error <> 0begin raiserror('failed',16,-1) rollback tran returnendupdate tblselect @rowcount = @@rowcount, @error = @@errorif @error <> 0begin raiserror('failed',16,-1) rollback tran returnendcommit tran==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
derrickleggett
Pointy Haired Yak DBA
4184 Posts |
Posted - 2004-05-15 : 16:30:02
|
| You might want to do some research on nested transactions for this Sam. They can come in really handy with this type of processing. It's pretty amazing what you can accomplish with them for consistency across a process.MeanOldDBAderrickleggett@hotmail.comWhen life gives you a lemon, fire the DBA. |
 |
|
|
SamC
White Water Yakist
3467 Posts |
Posted - 2004-05-15 : 18:28:59
|
The problem I had in hand was solved using Derick's UPDATE modification earlier. Nested TRANS? Hadn't thought about it much. I use BEGIN TRAN a little on some interactive work - safety net.I'd like to see an example of Nigel's suggestion applied to my problem. I didn't get enough traction from his post to complete the syntax myself:quote: Originally posted by nr Without a holdlock hint the shared lock taken by the select would be released immediately. Even if it wasn't two spids could take the shared lock at the same time and both pass the test.The two spids could then both perform the update - the first being overwritten by the second.For that code to work it would need something like(holdlock, tablockx) on the select to prevent the other spid performing the select until the update completes.
Sam |
 |
|
|
SamC
White Water Yakist
3467 Posts |
Posted - 2004-05-15 : 18:34:21
|
| Then, is this the mechanism Nigel was referring to?[CODE]BEGIN TRANIF EXISTS (SELECT * FROM dbo.ISSOS WITH HOLDLOCK, ROWLOCK WHERE ISSOID = @ISSOID AND RowID = @RowID) BEGIN -- Timestamp Valid? UPDATE dbo.ISSOS -- Mark this row deleted SET Deleted = 1 WHERE ISSOID = @ISSOIDEND ELSE BEGIN SET @ReturnMessage = 'Row was modified by another user before delete. Try again.' SET @ReturnValue = 1ENDCOMMIT TRAN[/CODE]And the lock on the row is held until the COMMIT TRAN ? Sam |
 |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-05-16 : 09:36:27
|
| It's a question you can answer yourself via a simple test using query analyser (hint - you should find it doesn't work).Create a tablecreate table a (i int, j int)insert a select 1, 1In one window executeBEGIN TRANIF EXISTS (SELECT * FROM a WITH (HOLDLOCK, ROWLOCK) WHERE j = 1 AND i = 1)beginselect 1endThat will check for existance and execute the select 1 and hold the locksExcute the same statement in another window. What you are looking for is for the statement to be blocked.Try the same thing with (HOLDLOCK, tablockx), (HOLDLOCK, updlock).To test what you believe will work set a few spids going in a loop doing the update and checking the results.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
SamC
White Water Yakist
3467 Posts |
Posted - 2004-05-16 : 09:51:20
|
| Thanks ... Nigel.Sam |
 |
|
|
|