简体   繁体   中英

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

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.

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.

您还可以对服务器实施一些轮询,保留行的上次更新记录,如果用户B在A之前更新记录,则更改位置,然后您可以通知用户A记录已更新,并且他的更改不会生效或您可以动态更新值。

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM