On-board account system balance concurrent update problem records

Source: Internet
Author: User
On an e-commerce platform, an online user reports a bug saying that the account balance information is not consistent with the transaction flow. It can be considered as a problem of concurrent database updates, so as to identify specific causes and provide solutions.

Symptom

Scenario Description

In the online accounting system, when the regular settlement is made to the seller and the high concurrency occurs, after the withdrawal of X yuan (assuming that the current user balance is X yuan) is 0, A sum of money is transferred to the Account (assuming y yuan). As a result, the account balance is changed to x + y yuan, resulting in incorrect user balance. PS: Changes to the account balance are updated in the transaction.

Environment Description

Mysql5.7 + InnoDB, transaction isolation level is REPEATABLE-READ

Scenario Simulation

We simplified the offline data structure and simulated the scenario. The data table is as follows:

'Account master table'

Create Table user (

UID int (11) not null comment 'Type ID + auto-incrementing sequence ',

Name varchar (32) default null,

Primary Key (UID)

) Engine = InnoDB default charset = utf8 comment = 'account master table'

'Account balance detail'

Create Table user_account (

UID int (11) not null,

Amount decimal (19,4) default 0 comment 'account balance ',

Primary Key (UID)

) Engine = InnoDB default charset = utf8 comment = 'account balance details'

Account type configuration

Create Table user_conf (

Type_id int (11) not null, description varchar (32) default null comment 'Type description', primary key (type_id )) engine = InnoDB default charset = utf8 comment = 'account type configuration'

The specific data is:

Select * from user;

+ ------- + ------ + | Uid | Name | + ------- + ------ +

| 10001 | A |

| 1, 10002 | B |

Select * From user_account;

+ ------- + ---------- + | Uid | amount | + ------- + ---------- +

| 10001/10.0000 |

| 10002/108.9900 |

Select * From user_conf;

+ --------- + -------------- + | Type_id | description | + --------- + -------------- +

| 100 | external account |

| 200 | internal account |

The transactions that simulate the concurrent operations of withdrawal (that is, the balance is reduced) and Accounting (that is, the balance plus) are as follows:

Session1-Withdrawal 10 RMB session2-account 20 RMB begin; select description from user_conf where type_id = 100; selectFrom user where uid = 10001 for update; // The User table is used for mutex select amount from user_account where uid = 10001; // 10.00 begin; select description from user_conf where type_id = 100; selectFrom user where uid = 10001 for update; // wating // watingupdate user_account set amount = 0.00 where uid = 10001; commit; get the lock select amount from user_account where uid = 10001; // 10.00 is recorded as 20 RMB. After calculation in the code, it should be 30 RMB update user_account set amount = 30.00 where uid = 10001; commit;

When the problem occurs, the user's balance is 30 yuan, that is, the user's withdrawal of 10 yuan is not reflected in the balance

Locate the cause

Those familiar with MySQL may already know that the problem is caused by snapshot reading at the REPEATABLE-READ isolation level.

Explanation:

At the RR level, a snapshot is generated for the first read operation. For visibility, only modifications committed by other transactions and modifications made by themselves before the first read are visible. Others are invisible.

Https://dev.mysql.com/doc/refman/5.7/en/glossary.html snapshot a representation of data at a particle time, which remains the same even as changes are committed by other transactions.

With Repeatable read isolation level, the snapshot is based on the time when the first read operation is completed MED.

Visibility Principle

Back to the preceding simulation scenario, session2 generates a snapshot in the SQL statement select description from user_conf where type_id = 100. Although session1 is submitted, it is still invisible, resulting in concurrent updates.

In addition, after the transaction is enabled, select... For update does not generate snapshots. you can experiment with them by yourself.

Solution

Solution 1

Change the REPEATABLE-READ isolation level to read-committed to see the latest committed data.

Solution 2

Add for update when reading 'account balance details' user _ account. force read the latest data of the row record, 2. if other transactions do not commit, the transaction will be blocked to ensure serial update.

Solution 3

Snapshots are generated in a delayed manner. After the transaction is started, the user table is used for mutex and the lock is applied directly for update. concurrent updates to multiple transactions are serialized.

Appendix: positioning process

For bug reporting users, query the transaction flow details and balance change details to confirm the account has problems.
Check whether there have been online changes in the accounting system in recent days.
Pull the MySQL General log of the Account Database and find the two transaction sessions for concurrent updates.
The isolation level set in the query database is RR. The application database connection pool configuration is queried, that is, the isolation level of the session is not configured. The database configuration is used.
Validation is caused by RR level (of course it can also be considered as caused by code problems)
It was confirmed that the account system went live one month ago and switched to another connection pool without setting the session isolation level. Previously, the isolation level of the configured session was read-committed.
Extended thinking

What are the applicable business scenarios at the MySQL RR level? If you are interested or have insights, you can leave a message to reply or send a private message ~~

On-board account system balance concurrent update problem records

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.