Skip to main content
5 of 7
The name of the DBMS of relevance is specified via tags, so I removed a reference from the title. Modified formatting..
MDCCL
  • 8.5k
  • 3
  • 31
  • 62

Why does this query results in deadlock?

I provide below the raw MySQL query and also the code in which I do that programatically. If two requests are being done at the same time results in the following error pattern:

SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction (SQL: update user_chats set updated_at = 2018-06-29 10:07:13 where id = 1)

If I execute the same query but without transaction block around it will work without error with many concurrent calls. Why ? (The transaction aquires lock, right ?)

Is there any way to solve this without locking the entire table ? (Want to try avoid table level locks)

I know that a lock is acquired for inserting/updating/deleting tables in MySql with InnoDB but still do not understand why the deadlock happens here and how to solve it in the most efficient way.

    START TRANSACTION;
    
    insert into `user_chat_messages` (`user_chat_id`, `from_user_id`, `content`) values (1, 2, 'dfasfdfk);
    update `user_chats` set `updated_at` = '2018-06-28 08:33:14' where `id` = 1;
    
    COMMIT;

Above is the raw query, but I do it in PHP Laravel Query Builder as follows:

    /**
     * @param UserChatMessageEntity $message
     * @return int
     * @throws \Exception
     */
    public function insertChatMessage(UserChatMessageEntity $message) : int
    {
        $this->db->beginTransaction();
        try
        {
            $id = $this->db->table('user_chat_messages')->insertGetId([
                    'user_chat_id' => $message->getUserChatId(),
                    'from_user_id' => $message->getFromUserId(),
                    'content' => $message->getContent()
                ]
            );

            //TODO results in lock error if many messages are sent same time
            $this->db->table('user_chats')
                ->where('id', $message->getUserChatId())
                ->update(['updated_at' => date('Y-m-d H:i:s')]);

            $this->db->commit();
            return $id;
        }
        catch (\Exception $e)
        {
            $this->db->rollBack();
            throw  $e;
        }
    }

DDL for the tables:

CREATE TABLE user_chat_messages
(
    id INT(10) unsigned PRIMARY KEY NOT NULL AUTO_INCREMENT,
    user_chat_id INT(10) unsigned NOT NULL,
    from_user_id INT(10) unsigned NOT NULL,
    content VARCHAR(500) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT user_chat_messages_user_chat_id_foreign FOREIGN KEY (user_chat_id) REFERENCES user_chats (id),
    CONSTRAINT user_chat_messages_from_user_id_foreign FOREIGN KEY (from_user_id) REFERENCES users (id)
);
CREATE INDEX user_chat_messages_from_user_id_index ON user_chat_messages (from_user_id);
CREATE INDEX user_chat_messages_user_chat_id_index ON user_chat_messages (user_chat_id);


CREATE TABLE user_chats
(
    id INT(10) unsigned PRIMARY KEY NOT NULL AUTO_INCREMENT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
Kristi Jorgji
  • 293
  • 2
  • 3
  • 7