MySQL: will a transaction lock the row

innodblockingMySQLtransaction

I haven't tried using MySQL transaction before, I just want to clarify something.

If two users execute a query at the very exact time, how MySQL would handle this?
e.g. the users is trying to update a record.

user1: update table set column = column – 4 where column_id = 1;

user2: update table set column = column – 7 where column_id = 1;

Now if I use transactions, will MySQL choose which query will be executed first and lock the second user until the first query is committed? Will that be a table lock or a row lock?

What if a third user will issue a select statement? What will be the value MySQL will return?

P.S. this will be on Innodb.

Best Answer

A single statement like that works the same with MyISAM or InnoDB, with a transaction or with autocommit=ON. It blocks enough to do the query, thereby blocking the other connection. When finished, the other connection proceeds. In all cases, the column is soon decremented by 11.

A third user may see the value decremented by 0 or 4 or 7 or 11. The "very exact time" is not really possible because, at some point in the execution of each statement, a single-threaded lock is checked/set/whatever. That is, they will be serialized, just so fast that you can't see it.

InnoDB locks only rows, not tables. (OK, DDL statement do bolder locks.)

What gets more interesting is a transaction that modifies two things, or that takes a noticeable amount of time:

Intention Case: Single item but taking time:

BEGIN;
SELECT something;
think about it for a while
UPDATE that something;
COMMIT;

The select needs to be written thus:

SELECT something  FOR UPDATE;

This tells other connections "I intend to update the row; please don't mess me up". (I bring up this example, because a lot of newbies miss this subtlety.)

Deadlock case: Messing with 2 things:

BEGIN;    -- in one connection
UPDATE thing_1;
UPDATE thing_2;
COMMIT;

BEGIN;    -- in another connection, at the "exact same time"
UPDATE thing_2;
UPDATE thing_1;
COMMIT;

This is the classic example of a deadlock -- each grabs one thing and then reaches for the other thing. Clearly it can't be made to work. One transaction is killed; the other completes. Hence, you must check for errors, so you can discover it.

The normal reaction to a deadlock is to replay the entire failed transaction. By then, the other connection will not be interfering, and it should proceed without trouble. (OK, yet another connection could create another deadlock.)

Delay Case: If the two connections grab multiple things in the same order, then one can be delayed until the other finishes. To keep this from "waiting forever", there is a default 50-second innodb_lock_wait_timeout. Your pair of simple UPDATEs is actually an example of this case. One will finish promptly; the other is stalled until the first finishes.

Note how a Deadlock can (in some cases) be turned into a Delay by consistently ordering the things you touch.

autocommit=1: With this setting and without calling BEGIN, each statement is effectively:

BEGIN;
your statement
COMMIT;

autocommit=0: This is trouble waiting to happen. When you perform a write query, a BEGIN is implicitly generated. However, it is your responsibility to eventually issue COMMIT. If you fail to do so, you will wonder why your system is hung. (Another common newbie bug.) My advice: "Never use =0".