Here is the scenario. This table Orders has an auto_increment column called orders_id. The table uses InnoDB storage engine. (This is not about inserting new records in the Orders table, its about how to avoid sending duplicate IDs to the processor)
orders_id cust_id name address
100 55 abc 123 street
101 12 def 456 street
For the next order, I calculate the next available Orders_id like so
$new_order_id_query = "SHOW TABLE STATUS LIKE ORDERS";
$result = tep_db_query($new_order_id_query);
$row = tep_db_fetch_array($result);
$new_order_id = $row['Auto_increment'];
Then I collect other information like name, address, items_ordered… and send it to the payment processor like this
102 44 xyz 44 Street
The problem is only sometimes when there are two or more orders at exactly the same time, I end up sending two orders with the same orders_id to the payment processor.
The question is how can I make sure that I am not sending a duplicate Orders_id to the Payment Processor?
I have been suggested to use last_insert_id() which may be right or wrong but I dont know how I can implement it.
I read about Locking Tables – Is that a good idea for a Transaction Environment and InnoDB? If so how can I implement it?
4
Answers
auto_increment columns normally do not require manipulation in your code. When you insert new record column defined with auto_increment is automatically incremented.
last_insert_id is used to obtain the value that was assigned to your automatically incremented field within your connection context.
I would not recommend locking table in your case, because you didn’t provide any grounds to do so in your problem statement.
As explained in my answer to your last question:
Collect the name, address, items_ordered, etc.
Insert relevant detail into the
orders
table, omitting to provide anid
(MySQL will automatically generate one for you, guaranteeing its uniqueness through the use of locks).Obtain the generated
id
from MySQL by asking it forlast_insert_id
(the actual function call will depend on your driver).Send to your payment processor.
You don’t need to calculate what the next order ID will be. Auto increment automatically makes the next ID for you when you insert a row into that table. That is the whole point of it.
All you need to do is run an insert that puts in all the other information into the table, without specifying a value for the auto_increment field.
If you want to find out what the order ID was of the row you just inserted, simply call last_insert_id() on the query result. I don’t know what
tep_db
is, as it’s not something I’ve used but I think you want the functiontep_db_insert_id()
.All techniques you’ve mentioned require that you open a database connection and keep it open between different HTTP requests (while you prevent other scripts instances from using it) so can benefit from a single database session. There’s no reliable way to do so.
I haven’t worked with osCommerce for ages (I’m surprised it still exists 🙂 but you basically have two possibilities:
I honestly think you need to save the order before redirecting to payment gateways. If you trust session data you’ll lose orders sooner or later; and you’ll lose payed orders, which is worse.