I'm developing warehouse system, that can manage product with different BBDs (best before dates). So table is quite simple (i'm using MySQL + PHP)
ID - PK, Autoincrement
ProductID - FK products
Quantity - positive, if put products to warehouse and negative if take from warehouse
BBD - best before date
OperationDate - DATETIME when operation was created
I some goods arrive warehouse, I simply add rows to this table, like
INSERT INTO warehouse (ProductID, Quantity, BBD, OperationDate) VALUES (1, 500, '2022-02-02', UTC_TIMESTAMP());
INSERT INTO warehouse (ProductID, Quantity, BBD, OperationDate) VALUES (1, 100, '2022-05-15', UTC_TIMESTAMP());
INSERT INTO warehouse (ProductID, Quantity, BBD, OperationDate) VALUES (1, 50, '2022-10-27', UTC_TIMESTAMP());
But the problem is, when I want to withdraw from warehouse certain amount of exact good.
For example, I have 2 orders (to take FROM warehouse)
First one for 550
pieces, and second one for 70
pieces.
What is the best way and algorythm to calculate, what Quantity
and what BBD
will go for each order?
In my example for first order will go:
500 pieces with bbd: 2022-02-02
50 pieces with bbd: 2022-05-15
in sql:
INSERT INTO warehouse (ProductID, Quantity, BBD, OperationDate) VALUES (1, -500, '2022-02-02', UTC_TIMESTAMP());
INSERT INTO warehouse (ProductID, Quantity, BBD, OperationDate) VALUES (1, -50, '2022-05-15', UTC_TIMESTAMP());
and for second order:
50 pieces with bbd: 2022-05-15
20 pieces with bbd: 2022-10-27
in sql:
INSERT INTO warehouse (ProductID, Quantity, BBD, OperationDate) VALUES (1, -50, '2022-05-15', UTC_TIMESTAMP());
INSERT INTO warehouse (ProductID, Quantity, BBD, OperationDate) VALUES (1, -20, '2022-10-27', UTC_TIMESTAMP());
Main thing - the worst BBD will left warehouse first.
How should I implement locks/transactions/etc. if there will be many incoming and outgoing orders in parallel?
My first though was, if I can somehow block for exact ProductID even for READ operations when I calculate what BBD to reduce. I tried to use LOCK TABLES
but it needs to lock every table in query, not so good solution. I tried to SELECT ... FOR UPDATE
, but I'm not sure will it prevent for reading same rows from another sessions.
So, what is the right way to get this?