I have a procedure that inserts n rows at a time. Each time it should pick up the MAX(BatchNo)
and insert it along with other columns.
Select @maxbatchno = MAX(batchno) from table1;
insert into table1 (name,phone,batchno)
select name,phone, maxbatchno from #temp;
Wouldn't there be concurrency issues with the above query? If there are multiple users trying to run this procedure wouldn't there be duplicates?
I think you are mixing entities. You have a "batch" entity, but it is hidden. If you have a table for that and use the table, you won't have a problem.
I actually assume that you want a NEW batch number, which would be larger than the previous value. Your version is just re-using the previous value, over and over. So:
create tables batches (
batchId int identity(1, 1) primary key,
createdAt datetime default getdate()
-- other columns here could be useful
);
create table @ids (batchId int);
insert into batches
output inserted.batchId into @ids
default values;
insert into table1 (name, phone, batchno)
select t.name, t.phone, i.batchId
from #temp t cross join
@ids i;
With this approach, you don't have to worry about concurrency issues.
Note: You could use a sequence instead. But I think that "batch" is a first-class entity and should have its own table.
(Talking from experience with similar scenarios here)
If you have a demo coming up very soon I would just go with:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRAN;
-- do your stuff here but don't forget the overall error handling...
COMMIT
However, as soon as you have the time - perhaps even after this demo - I highly recommend doing some stress testing (multi-threaded!) which incorporate comparing this SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
approach with the results from the more granular sp_getapplock
approach, which can be used if you absolutely want to make sure the inserts are processed single-threaded and your expected load is going to be very high. If your expected load won't be that high I'd just go with the first option, but I would be very interested to see the test results in terms of usability and performance. Here a sp_getapplock
example:
DECLARE @result INT;
EXEC @result = sp_getapplock
@Resource = 'MySessionsNameForThisApplock'
, @LockMode = 'Exclusive'
, @LockOwner = 'Session';
IF @result < 0
BEGIN
RAISERROR('Could not get applock - MySessionsNameForThisApplock.', 16, 1);
END;
ELSE
BEGIN
-- do your stuff here but don't forget the overall error handling...
EXEC @result = sp_releaseapplock
@Resource = 'MySessionsNameForThisApplock'
, @LockOwner = 'Session';
END;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.