Showing posts with label concurrency. Show all posts
Showing posts with label concurrency. Show all posts

Thursday, March 29, 2012

Database concurrency

I'm wondering whether the following code would work if users are RAPIDLY registering (assumption) WITH the same username.
public bool UsernamExists(string username){string sql ="SELECT true FROM [users] WEHRE username = @.username;";return Convert.ToBoolean(comm.ExecuteScalar());}public bool Signup(User user){bool usernameExists = UsernameExists(user.Username);if( usernameExists )return false;//update or insert sql for user etc blah blah}

If two users try to signup AT THE VERY SAME TIME (DOWN TO THE NANOSECOND), would this technique work? Do I have to wrap it in a transaction, stored procedure??


Thanks.

no that does not guarantee unique usernames.

You should add a unique constraint to your username column in the database to guarantee that duplicates cannot exist.

Then, you can still do your usernameexists check it you want, but you would also want to add an error handler (try/catch) to catch the exception that would occur in the unlikely event that two users simultaneously submitted the same usernames.

|||I know about unique column BUT would the technique I mentioned above work IN TERMS OF CODING? Like 2 users submitting AT THE VERY SAME TIME.|||

Yes the code would run, but...

if you dont have a unique constraint in your db, then you could end up with 2 records with the same username.

|||

Your code will not work because you have error in it

"SELECT true FROM [users]WHERE username = @.username;";

you have no comm object defined ad no parameter added to command. But if you update it you will have no guaranty that you will not have two user with the same name in your database. But you can modify you code to do something like this with transaction (safer) or not:

BEGIN TRAN

IF not exist(SELECT * FROM [users]WHERE username = @.username)
BEGIN
INSERT into [users](username)
Values (@.username)
SELECT 'True' [Result]
END
ELSE
SELECT 'False' [RESULT]

COMMIT TRAN

In this way you will save one round trip to SQL server an everything will be done in one shot and very fast.

Thanks


|||

I know you have to use the comm object, excluded it out for the simplicity.

I thought about wrapping my sql syntax in a transaction with row locking, but I'm not to keen on writing that much sql syntax. I like to keep it minimal.

Is there a way the comm object could "perform" the transaction automatically? Can you show me a simple example?

|||

Hi vze1r2ht

There is no way to make the comm object start a transaction automatically. You will need to start a transaction by explicitly calling SqlConnection.BeginTransaction() and assign the returned SqlTransaction object to a SqlCommand.

You can also perform this in a stored procedure by using BEGIN TRAN.

|||

Kevin Yu - MSFT:

Hi vze1r2ht

There is no way to make the comm object start a transaction automatically. You will need to start a transaction by explicitly calling SqlConnection.BeginTransaction() and assign the returned SqlTransaction object to a SqlCommand.

You can also perform this in a stored procedure by using BEGIN TRAN.

Thank you. Is there any major performance hit when using the SqlConnection.BeginTransaction() technique vs SQL's BEGIN Tran? Because of the massive amounts of transactions I will need to write for my classes, it will alll be inline if it was SQL and NOT stored procedures (hard to maintain).

|||

Hi,

As far as I can see, they are the same. Not much differences.

Database concurrency

we are developing an ASP.NET application with SqlServer at backend..
there are an supplier and about 3000 customer, and each customer has about
3-4 users. they are selling mobile phone counters.
while a sale occurs, we are selecting customers stock amount, if it is
bigger then sale amount, we are updating its stock, and we increment
suppliers stock. The query is like that :
DECLARE @.StockAmount int
SELECT @.StockAmount = Amont FROM Stocks WHERE CustomerId = @.BuyerCustomerId
IF @.StockAmount > @.SaleAmount
UPDATE Stocks SET amount = @.StockAmount - @.SaleAmount WHERE CustomerId =
@.BuyerCustomerId
SELECT @.SuppliersStockAmount = Amont FROM Stocks WHERE CustomerId =
@.SellerCustomerId
UPDATE Stocks SET amount = @.StockAmount + @.SaleAmount WHERE CustomerId =
@.SellerCustomerId
i know, each customer has got not so many users and a concurrency problem
seems to be not a big possibility. but there is just a 1 supplier record and
i think conlicts are possible. how can i alter this problem. after a
research, i found
SELECT @.SuppliersStockAmount = Amont FROM Stocks WITH (XLOCK ROWLOCK) WHERE
CustomerId = @.SellerCustomerId
seems to work fine for us, but it will block the row untill the transaction
finishes. any approaches are appreciated. thanks.Try
SELECT @.SuppliersStockAmount = Amont FROM Stocks WITH (UPDLOCK) WHERE
CustomerId = @.SellerCustomerId
Some amount of blocks is unavoidable.
This lock hint won't block others for reading. It will assure that the data
has not changed since you last read it
"The Crow" <q> wrote in message
news:ODUI3bVVFHA.2984@.tk2msftngp13.phx.gbl...
> we are developing an ASP.NET application with SqlServer at backend..
> there are an supplier and about 3000 customer, and each customer has about
> 3-4 users. they are selling mobile phone counters.
> while a sale occurs, we are selecting customers stock amount, if it is
> bigger then sale amount, we are updating its stock, and we increment
> suppliers stock. The query is like that :
> DECLARE @.StockAmount int
> SELECT @.StockAmount = Amont FROM Stocks WHERE CustomerId =
@.BuyerCustomerId
> IF @.StockAmount > @.SaleAmount
> UPDATE Stocks SET amount = @.StockAmount - @.SaleAmount WHERE CustomerId =
> @.BuyerCustomerId
> SELECT @.SuppliersStockAmount = Amont FROM Stocks WHERE CustomerId =
> @.SellerCustomerId
> UPDATE Stocks SET amount = @.StockAmount + @.SaleAmount WHERE CustomerId =
> @.SellerCustomerId
> i know, each customer has got not so many users and a concurrency problem
> seems to be not a big possibility. but there is just a 1 supplier record
and
> i think conlicts are possible. how can i alter this problem. after a
> research, i found
> SELECT @.SuppliersStockAmount = Amont FROM Stocks WITH (XLOCK ROWLOCK)
WHERE
> CustomerId = @.SellerCustomerId
> seems to work fine for us, but it will block the row untill the
transaction
> finishes. any approaches are appreciated. thanks.
>|||You can use locking hint "UPDLOCK" or you can modify the statement and use
something like:
UPDATE Stocks
SET amount = amount - @.SaleAmount
WHERE CustomerId = @.BuyerCustomerId and amount > @.SaleAmount
...
AMB
"The Crow" wrote:

> we are developing an ASP.NET application with SqlServer at backend..
> there are an supplier and about 3000 customer, and each customer has about
> 3-4 users. they are selling mobile phone counters.
> while a sale occurs, we are selecting customers stock amount, if it is
> bigger then sale amount, we are updating its stock, and we increment
> suppliers stock. The query is like that :
> DECLARE @.StockAmount int
> SELECT @.StockAmount = Amont FROM Stocks WHERE CustomerId = @.BuyerCustomerI
d
> IF @.StockAmount > @.SaleAmount
> UPDATE Stocks SET amount = @.StockAmount - @.SaleAmount WHERE CustomerId =
> @.BuyerCustomerId
> SELECT @.SuppliersStockAmount = Amont FROM Stocks WHERE CustomerId =
> @.SellerCustomerId
> UPDATE Stocks SET amount = @.StockAmount + @.SaleAmount WHERE CustomerId =
> @.SellerCustomerId
> i know, each customer has got not so many users and a concurrency problem
> seems to be not a big possibility. but there is just a 1 supplier record a
nd
> i think conlicts are possible. how can i alter this problem. after a
> research, i found
> SELECT @.SuppliersStockAmount = Amont FROM Stocks WITH (XLOCK ROWLOCK) WHE
RE
> CustomerId = @.SellerCustomerId
> seems to work fine for us, but it will block the row untill the transactio
n
> finishes. any approaches are appreciated. thanks.
>
>|||This is the SQL Server Books Online explanations :
UPDATE LOCK :
Used on resources that can be updated. Prevents a common form of deadlock
that occurs when multiple sessions are reading, locking, and potentially
updating resources later.
UPDLOCK :
Takes update locks instead of shared locks. Cannot be used with NOLOCK or
XLOCK.
so, shared lock as u may know doesnt prevent reading data but modyfying,
which is not the case.|||UPDATE Stocks
SET amount = amount - @.SaleAmount
WHERE CustomerId = @.BuyerCustomerId and amount > @.SaleAmount
this statement "SELECT"s the suitable row aquiring update lock which behaves
same as shared lock, and then converts it exclusive lock prior to doing
actual update. isnt it?