Можете ли вы выполнить несколько атомарных коммитов, используя одно и то же соединение с MySQLdb? - PullRequest
0 голосов
/ 07 мая 2018

Я хотел бы иметь возможность выполнять атомарные коммиты, используя один и тот же объект соединения, используя библиотеку MySQLDb в Python3. Я не думаю, что необходимо создавать два сетевых соединения с базой данных только для выполнения нескольких атомарных коммитов, но, похоже, ситуация такова. Является ли единственной альтернативой для создания пула соединений?

Например, я хотел бы иметь возможность сделать что-то вроде этого

conn = MySQLdb.connect(host="1.2.3.4", port=1234, user="root", passwd="x", db="test")

try:
    cur = conn.cursor()
    cur.execute("insert into my_table values (1, 2, 3)")
    cur.execute("insert into my_table values (4, 5, 6)")

    cur1 = conn.cursor()
    cur1.execute("insert into my_table values (12, 22, 32)")
    cur1.execute("insert into my_table values (42, 52, 62)")

    # Commit the last 2 inserts first
    # This won't work because cursor.commit() doesn't exist
    cur1.commit()

    # Now commit the first two inserts
    cur.commit() # Again, this won't work

except FailedTransaction as ex:
   # Rollback the actual transaction that failed.
   # Cursor aren't transactions, but there is no transaction
   # object so this is the best I can come up with. 
   ex.cursor.rollback()

conn.close()

1 Ответ

0 голосов
/ 07 мая 2018

Нет, MySQL не имеет разных «уровней» транзакций в сеансе. Всего одна текущая транзакция и COMMIT или ROLLBACK влияют на всю транзакцию.


Я думаю, что мы можем открыть два соединения с MySQL одновременно. Для этого не требуется пул соединений. (Пул соединений был бы хорош по другим причинам).

conn1 = MySQLdb.connect(host="1.2.3.4", port=1234, user="root", passwd="x", db="test")
conn2 = MySQLdb.connect(host="1.2.3.4", port=1234, user="root", passwd="x", db="test")

Если мы получим два соединения, то мы сможем выполнять транзакции независимо для каждого соединения , Но это, вероятно, не сработает для вашего варианта использования. Предполагая, что InnoDB, если строка, вставленная в первое соединение, является «самым высоким» значением в ключе кластера, InnoDB передает исключительную блокировку индекса до конца индекса, не позволяя другим сеансам выполнять вставки с более высокими значениями в ключе кластера. (Второй сеанс будет блокироваться до тех пор, пока не будут получены требуемые блокировки; этого не произойдет, пока сеанс, удерживающий монопольную блокировку, не снимет его с помощью либо ROLLBACK, либо COMMIT.)

И проблема блокировки распространяется на все индексы, а не только на ключ кластера.

Пул соединений не решит эту проблему.


Исключительные замки, на которые я ссылаюсь, это "разрывные замки". Нам пришлось бы обходить блокировку, если мы выполняем вставки в одну и ту же таблицу, чтобы избежать блокировок, ожидая блокировок, когда эти блокировки удерживаются сеансом, управляемым нашей программой.

https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_gap_lock

https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html

...