Application Locks (or Mutexes) in SQL Server 2005

Application locks aren't a well known area of locking in SQL Server, but they can be very useful for special
scenarios. They work in an analogous way to the lock() construct in .Net and
are basicaly user defined mutexes in SQL Server.

An application lock is a bit different than other kinds of SQL Server locks though. While other locks lock schema
or data, application locks lock a part of your code. There are 2 stored procedure that are used
for this: sp_getapplock and sp_releaseapplock.

If an application lock owner is a transaction, the lock gets automatically released when the transaction ends.

However to be able to call sp_getapplock a user calling the stored procedure must meet one of these conditions:

is dbo

is in the db_owner role

is the DB Principal ID (e.g. guest)

is in the DB Principal ID role (e.g. public)

Best understood with an example...

Note that application locks aren't taken on any data like standard locks. Let's illustrate with some
code derived from above code. We need 3 batches:

Batch 1

Batch 2

Batch 3

BEGINTRANEXEC @res = sp_getapplock ....
SELECT *
FROM Person.Address

BEGINTRANEXEC @res = sp_getapplock ....
SELECT *
FROM Person.Address

SELECT *
FROM Person.Address

Run batch 1: Begin a transaction, get an application lock and select data from
Person.Address, but don't
release the lock nor end the transaction.

Run batch 2:
Begin a transaction, which will try to get an application lock but it won't be able to since the
application lock with the same name (@Resource) already exists. The batch will wait until
the lock with the existing name (@Resource) is released or the transaction is ended which
automatically releases the application lock.

Run batch 3:
This will always run disregarding the application lock altogether since there are no real
locks on data.

... and of course with an another example

A great example of application locks is a typical business logic problem of inserting data
if it doesn't exist and update it if it does. I've written about this in this
blog post. In it I
looked at the locking being held and the post comments have great value. But however you try to make
this work you'll always run into some concurrency issues. If you put the whole thing into a transaction then you’ll get into situations with violating PK constraints when inserting data. Another option is to use XLOCK and
HOLDLOCK hints in a transaction but this can result in a deadlock which is even worse that the first situation.
Application locks prove to be a very good solution to this:

If you run the stored procedure in Query Window 1 and after 5 second your run the stored
procedure in Query Window 2 you'll see that the whole code between sp_getapplock
and sp_releaseapplock
won't execute until the stored procedure in Query Window 1 finishes.

If all of your update/insert logic follows uses this pattern then you'll never get
concurrency issues.
Of course this method doesn't apply to all environments, so if you can use it requires some testing and design considerations.

Conclusion

While not often used they can come in handy in complex business logic cases. You can see that an application lock
simply locks the part of your T-SQL code and not actual data. So to achieve mutual exclusion (mutex),
all access has to follow this same lock acquisition pattern using sp_getapplock and sp_releaseapplock.
This is of course best achieved with stored procedures which is another plus in favor of them over ad-hoc (parameterized) queries.