How to properly use transactions and locks to ensure database integrity?

后端 未结 2 568
广开言路
广开言路 2020-12-15 01:16

I develop an online reservation system. To simplify let\'s say that users can book multiple items and each item can be booked only once. Items are first added to the shoppin

2条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-15 01:46

    1. Other user that tries to book same item at the same time will be handled correcly. Will his transaction T2 wait until T1 is done?

    Yes. While active transaction keeps FOR UPDATE lock on a record, statements in other transactions that use any lock (SELECT ... FOR UPDATE, SELECT ... LOCK IN SHARE MODE, UPDATE, DELETE) will be suspended untill either active transaction commits or "Lock wait timeout" is exceeded.

    2. Payment using PayPal or Stripe may take some time. Wouldn't this become a problem in terms of performance?

    This will not be a problem, as this is exactly what is necessary. Checkout transactions should be executed sequentially, ie. latter checkout should not start before former finish.

    3. Items availability will be shown correctly all the time (items should be available until checkout succeeds). Should these read-only selects use shared lock?

    Repeatable reads isolation level ensures that changes made by a transaction are not visible until that transaction is commited. Therefore items availability will be displayed correctly. Nothing will be shown unavailable before it is actually paid for. No locks are necessary.

    SELECT ... LOCK IN SHARE MODE would cause checkout transaction to wait until it is finished. This could slow down checkouts without giving any payoff.

    4. Is it possible that MySql rollbacks transaction by itself? Is it generally better to retry automatically or display an error message and let user try again?

    It is possible. Transaction may be rolled back when "Lock wait timeout" is exceeded or when deadlock happens. In that case it would be a good idea to retry it automatically.
    By default suspended statements fail after 50s.

    5. I guess its enough if I do SELECT ... FOR UPDATE on items table. This way both request caused by double click and other user will have to wait till transaction finishes. They'll wait because they also use FOR UPDATE. Meanwhile vanilla SELECT will just see a snapshot of db before the transaction, with no delay though, right?

    Yes, SELECT ... FOR UPDATE on items table should be enough.
    Yes, these selects wait, because FOR UPDATE is an exclusive lock.
    Yes, simple SELECT will just grab value as it was before transaction started, this will happen immediately.

    6. If I use JOIN in SELECT ... FOR UPDATE, will records in both tables be locked?

    Yes, SELECT ... FOR UPDATE, SELECT ... LOCK IN SHARE MODE, UPDATE, DELETE lock all read records, so whatever we JOIN is included. See MySql Docs.

    What's interesting (at least for me) everything that is scanned in the processing of the SQL statement gets locked, no matter wheter it is selected or not. For example WHERE id < 10 would lock also the record with id = 10!

    If you have no indexes suitable for your statement and MySQL must scan the entire table to process the statement, every row of the table becomes locked, which in turn blocks all inserts by other users to the table. It is important to create good indexes so that your queries do not unnecessarily scan many rows.

提交回复
热议问题