Thari
Thari

Reputation: 49

Concurrent mutiuser access php+mysql

Im going to develop Stock maintaining system using php+mysql. which will runs on server machine, so many users can update stock data. (in/out)

Im currently working on this system. I have following problems.

User A opens record “A”. ex- val=10
User B opens record “A”. ex - val=10
User A saves changes to record “A”. ex - val=10+2=12 (add 3 items, then stock should be 12)
User B saves changes to record “A”. ex - here i need to get record "A" value AS = 12, then B update val=12+3=15. (then add 3 items final stock will be 15)

In this example, User A’s changes are lost – replaced by User B’s changes.

I know mysql Innodb facilitate row level locking. My question is ,

is innodb engine do concurrent control ; and is this enough to (Innodb) to avoid "lost update" problem. or need to do extra coding to avoid this problem.

Is this enough please tell me how innodb works with my previous example. (lost update)

(sorry for my bad english)

thanks

Upvotes: 3

Views: 1135

Answers (5)

Tyzoid
Tyzoid

Reputation: 1078

Judging by comments left, I think it prudent to respond with some pointers I have come across, in case someone needs to.

If you only want to update a value by an offset, you can do this quite easily and atomically. Assume the following data:

+----+--------+-------+
| id | name   | price |
+----+--------+-------+
| 1  | Foo    | 49    |
| 2  | Bar    | 532   |
| 3  | Foobar | 24    |
+----+--------+-------+

We can now run the following queries to add one to the price:

select id, price from prices where name like "Foo";
// Later in the application
update prices set price=50 where id=1;

This is the non-concurrent/non-atomic way to do this, assuming that there is no changes or fetches in between the two queries. A more atomic way to do this, is the following.

select id, price from prices where name like "Foo";
// Later in the application
update prices set price=price+1 where id=1;

Here, this query allows us to increment the price in one query, eliminating the ability for others to come and update between two queries.

Additionally, there are methods of updating data safely, where the nature of the update is not a simple addition or subtraction. Let's say, here, that we have the following data:

+----+----------+---------------------+
| id | job_name | last_run            |
+----+----------+---------------------+
| 1  | foo_job  | 2016-07-13 00:00:00 |
| 2  | bar_job  | 2016-07-14 00:00:00 |
+----+----------+---------------------+

In this case, we have multiple different clients, where all clients can do any job. We then need a way to dispatch work to one client, and only one client.

We can either use a transaction, where we will error out if the record has been updated or we can use a technique called CAS, or Compare and Swap.

Here's how we do this in MySQL:

update jobs set last_run=NOW() where id=1 and last_run='2016-07-13 00:00:00'

Then, in the data returned from mysql, we can tell the number of rows affected. If we have affected a row, then we have successfully updated it, and the job is ours. If there were no rows updated, then another machine has updated it, claiming the job there.

This works because any update from our application will cause the column to change, and since the column's value is a condition for completing the updated, it will avoid concurrent changes, allowing the application to decide what occurs next.

Upvotes: 0

user1439838
user1439838

Reputation: 131

You can use two tables for this purpose. First - StockItems with item name, id, and count. Second - StockActivities with item id and operation amount.

To add or remove items from stock you need to insert records to the second table StockActivities, with item id and quantity that is added / removed.

    item id:1, qnt: +10
    item id:1, qnt: +1
    item id:10, qnt: -2

Field count of StockItems table should be "read only" for users and should be calculated based on StockActivities table. For example, you can create after insert trigger for StockActivities table that will update count field of added / removed stock item.

Upvotes: 1

Lawrence Cherone
Lawrence Cherone

Reputation: 46620

You could also implement some polling to the server, keep a record of the last update of the row and if it changes where if user B updates the record before A then you can notify user A that the record has been updated and that his changes wont take effect or you could update the values dynamically.

Upvotes: 1

Poni
Poni

Reputation: 11327

Look, there's something called "versioning".

The idea is simple:
When a user opens a record, he also gets the version number.
When he saves changes to that record, at the sql level, the update is conditional, meaning that the update will happen ONLY if the current version is the same. This update also increases the version by one.

This way ensures you're not writing to a "stale" copy of your record.

Hope it's clear.

Upvotes: 2

Litty
Litty

Reputation: 1876

InnoDB allows concurrent access, so User A and User B could definitely be handling the same data. User A will update the row based on his/her data, then User B can do the same -- ultimately resulting in User A's loss of data.

You should consider an alternative, if every update is vital to keep. For example, if both users are updating a blog article, you could make a new table that holds all these edits. Both user's edits would be preserved, despite when they retrieved the article content. When the article is retrieved, you can check when the most recent edit occurred and retrieve that instead.

Upvotes: 2

Related Questions