English 中文(简体)
mySQL - Prevent double booking
原标题:

I am trying to work out the best way to stop double booking in my application.

I have a table of unique id s each can be sold only once.

My current idea is to use a transaction to check if the chosen products are available, if they are then insert into a status column that it is reserved along with inserting a time of update then if the user goes on to pay I update the status to sold .

Every 10 mins I have a cron job check for status = reserved that was updated more than 10 mins ago and delete such rows.

Is there a better way? I have never used transactions (I have just heard the word banded around) so if someone could explain how I would do this that would be ace.

最佳回答

What you re attempting to do with your "reserved" status is essentially to emulate transactional behavior. You re much better off letting an expert (mysql) handle it for you.

Have a general read about database transactions and then how to use them in MySQL. They aren t too complicated. Feel free to post questions about them here later, and I ll try to respond.

Edit: Now that I think about your requirements... perhaps only using database transactions isn t the best solution - having tons of transactions open and waiting for user action to commit the transactions is probably not a good design choice. Instead, continue what you were doing with "status"="reserved" design, but use transactions in the database to set the value of "status", to ensure that the row isn t "reserved" by two users at the same time.

问题回答

despite what others here have suggested, transactions are not the complete solution.

sounds like you have a web application here and selecting and purchasing a reservation takes a couple of pages (steps). this means you would have to hold a transaction open across a couple of pages, which is not possible.

your approach (status column) is correct, however, i would implement it differently. instead of a status column, add two columns: reserved_by and reserved_ts.

  • when reserving a product, set reserved_by to the primary key of the user or the session and reserved_ts to now().
  • when looking for unreserved products, look for ones where reserved_ts is null or more than 10 minutes old. (i would actually look for a couple minutes older than whatever you tell your user to avoid possible race conditions.)
  • a cron job to clear old reservations becomes unnecessary.

You do not need to have any added state to do this.

In order to avoid dirty reads, you should set the database to an isolation level of that will avoid them. Namely, REPEATABLE READ or SERIALIZABLE.

You can set the isolation level globally, or session specific. If all your sessions might need the isolation, you may as well set it globally.

Once the isolation level is set, you just need to use a transaction that starts before you SELECT, and optionally UPDATEs the status if the SELECT revealed that it wasn t reserved yet.





相关问题
SQL SubQuery getting particular column

I noticed that there were some threads with similar questions, and I did look through them but did not really get a convincing answer. Here s my question: The subquery below returns a Table with 3 ...

please can anyone check this while loop and if condition

<?php $con=mysql_connect("localhost","mts","mts"); if(!con) { die( unable to connect . mysql_error()); } mysql_select_db("mts",$con); /* date_default_timezone_set ("Asia/Calcutta"); $date = ...

php return a specific row from query

Is it possible in php to return a specific row of data from a mysql query? None of the fetch statements that I ve found return a 2 dimensional array to access specific rows. I want to be able to ...

Character Encodings in PHP and MySQL

Our website was developed with a meta tag set to... <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> This works fine for M-dashes and special quotes, etc. However, I ...

Pagination Strategies for Complex (slow) Datasets

What are some of the strategies being used for pagination of data sets that involve complex queries? count(*) takes ~1.5 sec so we don t want to hit the DB for every page view. Currently there are ~...

Averaging a total in mySQL

My table looks like person_id | car_id | miles ------------------------------ 1 | 1 | 100 1 | 2 | 200 2 | 3 | 1000 2 | 4 | 500 I need to ...

热门标签