Showing posts with label legacy. Show all posts
Showing posts with label legacy. Show all posts

Friday, March 9, 2012

Limiting concurrent execution of a T-SQL stored procedure

Hello,

I have a quite large set of legacy stored procedures. The stored procedures are not reentrant, i.e. can not safely be executed in parallel by multiple threads. The procedures are not called multiple times simultaneously in the system, because of this restriction. There's however no explicit constraint to prevent multiple calls to these stored procedures and thus it's possible to e.g. accidentally call the procedures many times simultaneously.

My problem is, how to prevent multiple simultaneous executions of the stored procedures? Is there a native way to do this? In modern programming languages there are language constructs to prevent simultaneous access to code and variables (synchronized in Java, lock in C#). Is there something similar in T-SQL? What could be a workaround?

One options could be to use SQL Server jobs to prevent simultaneous accesss - only one instance of a job can be running at time. This is, however, problematic since if the job cannot be started because another instance is already running, the second instance will never be started. This is not what I won't.

JM

Refer to Books Online about the use of sp_getapplock and sp_releaseapplock.

Also, refer to this post. And this one.

|||

Thanks Arnie for your quick and good answer!

r,

JM

|||

Yes..

You can achive it using few tricks..using sp_getapplock.

But you need a wrapper storedproc or batch for this. Check the following example it will help you to desing your wrapper sp/batch statement.

Sample:

Code Snippet

Create table MyTable

(

RowId int identity(1,1),

HitStartedAt datetime,

HitTimestamp datetime,

UserName varchar(100)

)

Go

Create proc LegacyProc (@.user varchar(100), @.CalledTime datetime)

as

Begin

Insert Into MyTable

Values(@.CalledTime, getdate(), @.user);

--To wait for 10 sec : not required for your procedures, producing the latency to check the concurrent users action

WAITFOR DELAY '000:00:10'

End

Go

Create Proc MyProc

(

@.user varchar(100)

)

as

Begin

Declare @.PorcName as NVarchar(1000), @.CalledTime datetime

Begin Tran

--To get the Current SP Name, it should be unique for each SP / each batch

SET @.PorcName =object_name(@.@.ProcID)

SET @.CalledTime = Getdate()

--Lock the Current Proc

Exec sp_getapplock @.Resource = @.PorcName, @.LockMode = 'Exclusive'

--Execute Your Legacy Procedures

Exec LegacyProc @.user, @.CalledTime

--Release the lock

Exec sp_releaseapplock @.Resource = @.PorcName

Commit Tran

End

Friday, February 24, 2012

Limit to one value in fld b for given value in field a

Okay, i have a problem, which would be easy in a well-normalized db,
but im working in a legacy app here, and can't normalize the db because
it would break the existing apps around it.
I have a manifest table which essentially acts as both a header & line-items
table.
There is a MANIFESTID field which serves to link the lineitems together onto
one
manifest. There is also an ACTION field, which serves to indicate whether
the
manifest is for delivery or for pickup.
I dont know if it really is this hard, or if im just brain-freezing here,
but here is what
i'm trying to do... i want to put in some sort of constraint so that for all
the lines which
have any given MANIFESTID, the ACTION field is the same on all of them.
Thanks in advance,
- Arthur Dent.Not sure if I fully understood your problem, but in SQL Server, you cannot
create a constraint declaratively which can enforce some logic based on
multiple rows.
A general alternative is to use a after trigger with a rollback statement.
This is somewhat prohibitive in high performance systems since the logic can
turn out to be complex depending on your schema. In rare cases, you might be
able to work it out with a scalar udf used in a check constraint as well.
Anith|||As example for clarification,
ACTION is declared with a check as either D or P or Delivery or Pickup.
I might have 5 rows where the ManifestID is <10>. What i want is to be able
to say
For All Rows Where MANIFESTID = 10,
ACTION on ALL 5 Rows can be 'D' or 'P', but they ALL
must be 'D' or ALL must be 'P'
"Anith Sen" <anith@.bizdatasolutions.com> wrote in message
news:%23Y4JaqG7FHA.3544@.TK2MSFTNGP09.phx.gbl...
> Not sure if I fully understood your problem, but in SQL Server, you cannot
> create a constraint declaratively which can enforce some logic based on
> multiple rows.
> A general alternative is to use a after trigger with a rollback statement.
> This is somewhat prohibitive in high performance systems since the logic
> can turn out to be complex depending on your schema. In rare cases, you
> might be able to work it out with a scalar udf used in a check constraint
> as well.
> --
> Anith
>|||On Fri, 18 Nov 2005 13:53:12 -0500, Arthur Dent wrote:

>As example for clarification,
>ACTION is declared with a check as either D or P or Delivery or Pickup.
>I might have 5 rows where the ManifestID is <10>. What i want is to be able
>to say
>For All Rows Where MANIFESTID = 10,
>ACTION on ALL 5 Rows can be 'D' or 'P', but they ALL
>must be 'D' or ALL must be 'P'
Hi Arthur,
This might be one of those cases where a UDF + CHECK constraint will
work:
CREATE FUNCTION dbo.CheckNoOthers
(@.ManifestID int, @.Action char(1))
RETURNS char(3)
AS
BEGIN
DECLARE @.Result char(3)
IF EXISTS (SELECT *
FROM YourTable
WHERE ManifestID = @.ManifestID
AND Action <> @.Action)
BEGIN
SET @.Result = 'No'
END
ELSE
BEGIN
SET @.Result = 'Yes'
END
RETURN @.Result
go
ALTER TABLE YourTable
ADD CONSTRAINT NoOthers
CHECK (dbo.CheckNoOthers(ManifestID, Action) = 'Yes')
go
(untested - see www.aspfaq.com/5006 if you prefer a tested reply)
Best, Hugo
--
(Remove _NO_ and _SPAM_ to get my e-mail address)|||Yah, that looks like it would probably work. Thanks!
"Hugo Kornelis" <hugo@.pe_NO_rFact.in_SPAM_fo> wrote in message
news:qgq1o1pc00til4dvnk7h2jk7nssscm6vk2@.
4ax.com...
> On Fri, 18 Nov 2005 13:53:12 -0500, Arthur Dent wrote:
>
> Hi Arthur,
> This might be one of those cases where a UDF + CHECK constraint will
> work:
> CREATE FUNCTION dbo.CheckNoOthers
> (@.ManifestID int, @.Action char(1))
> RETURNS char(3)
> AS
> BEGIN
> DECLARE @.Result char(3)
> IF EXISTS (SELECT *
> FROM YourTable
> WHERE ManifestID = @.ManifestID
> AND Action <> @.Action)
> BEGIN
> SET @.Result = 'No'
> END
> ELSE
> BEGIN
> SET @.Result = 'Yes'
> END
> RETURN @.Result
> go
> ALTER TABLE YourTable
> ADD CONSTRAINT NoOthers
> CHECK (dbo.CheckNoOthers(ManifestID, Action) = 'Yes')
> go
> (untested - see www.aspfaq.com/5006 if you prefer a tested reply)
> Best, Hugo
> --
> (Remove _NO_ and _SPAM_ to get my e-mail address)