mysql insert race condition

后端 未结 8 1433
暗喜
暗喜 2020-12-09 06:19

How do you stop race conditions in MySQL? the problem at hand is caused by a simple algorithm:

  1. select a row from table
  2. if it doesn\'t exist, insert it
相关标签:
8条回答
  • 2020-12-09 06:38

    You prevent duplicate rows very simply by putting unique indexes on your tables. That has nothing to do with LOCKS or TRANSACTIONS.

    Do you care if an insert fails because it's a duplicate? Do you need to be notified if it fails? Or is all that matters that the row was inserted, and it doesn't matter by whom or how many duplicates inserts failed?

    If you don't care, then all you need is INSERT IGNORE. There is no need to think about transactions or table locks at all.

    InnoDB has row level locking automatically, but that applies only to updates and deletes. You are right that it does not apply to inserts. You can't lock what doesn't yet exist!

    You can explicitly LOCK the entire table. But if your purpose is to prevent duplicates, then you are doing it wrong. Again, use a unique index.

    If there is a set of changes to be made and you want an all-or-nothing result (or even a set of all-or-nothing results within a larger all-or-nothing result), then use transactions and savepoints. Then use ROLLBACK or ROLLBACK TO SAVEPOINT *savepoint_name* to undo changes, including deletes, updates and inserts.

    LOCK tables is not a replacement for transactions, but it is your only option with MyISAM tables, which do not support transactions. You can also use it with InnoDB tables if row-level level locking isn't enough. See this page for more information on using transactions with lock table statements.

    0 讨论(0)
  • 2020-12-09 06:40

    In case insert ignore doesnt fit for you as suggested in the accepted answer , so according to the requirements in your question :

    1] select a row from table
    2] if it doesn't exist, insert it

    Another possible approach is to add a condition to the insert sql statement, e.g :

    INSERT INTO table_listnames (name, address, tele)
    SELECT * FROM (SELECT 'Rupert', 'Somewhere', '022') AS tmp
    WHERE NOT EXISTS (
        SELECT name FROM table_listnames WHERE name = 'Rupert'
    ) LIMIT 1;
    

    Reference: https://stackoverflow.com/a/3164741/179744

    0 讨论(0)
提交回复
热议问题