команда не может быть использована внутри транзакции). API не должен пытаться магически абстрагировать удаленные транзакции; это следует оставить пользователю. Вы можете отключить это поведение с помощью автоматической фиксации, но опять же, это нарушает код, который не ожидает его.

ющий код, использующий python 2.6.6 и MySQLdb 1.2.2, вызываетКоманды не синхронизированы; Вы не можете запустить эту команду сейчас MySQLdb исключение:

import MySQLdb

conn = MySQLdb.connect( db="test", user="root" )
cursor = conn.cursor( MySQLdb.cursors.DictCursor )

cursor.execute( "BEGIN; CREATE TABLE t1 ( t1_id INT PRIMARY KEY AUTO_INCREMENT ); COMMIT;" )
cursor.execute( "BEGIN; CREATE TABLE t2 ( t2_id INT PRIMARY KEY AUTO_INCREMENT ); COMMIT;" )

Исключение возникает при выполнении второго запроса. Как я читал, исключение обычно вызвано ограничениями реализации MySQL C API, которые запрещают параллельное выполнение запросов.

Если я воссоздаю объект курсора между двумя вышеуказанными запросами, проблема решается, но, к сожалению, решение не кажется мне идеальным. У меня есть очень простая абстракция над подключением к базе данных и выполнением запроса, и я предпочел бы не пересоздавать курсор после каждого выполнения запроса, поскольку он (насколько я понимаю) фиксирует текущую транзакцию и потенциально может иметь другие побочные эффекты.

Поэтому мой вопрос: каковы другие способы избежать этого исключения? Как подготовить объект курсора для выполнения следующего запроса? Может быть, есть какой-то метод, ожидаемый от API-интерфейса DB Python, который будет относительно нейтральным при использовании других интерфейсов базы данных и обойдет проблему в случае MySQLdb?

Заранее спасибо за ваше время и помощь :)

Редактировать: После того, как я опубликовал вопрос, я начал читать спецификацию Python DB API, чтобы узнать о побочных эффектах разрушения курсора (я больше не уверен насчет фиксации транзакции :)), и обнаружил следующее, альтернативное решение:

cursor.execute( "BEGIN; CREATE TABLE t1 ( t1_id INT PRIMARY KEY AUTO_INCREMENT ); COMMIT;" )
while cursor.nextset() is not None: pass
cursor.execute( "BEGIN; CREATE TABLE t2 ( t2_id INT PRIMARY KEY AUTO_INCREMENT );

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

Ответы на вопрос(1)

Решение Вопроса

начиная транзакцию по первой команде и имея собственный вызов API для ее фиксации, поэтому:

cursor.execute( "CREATE TABLE t1 ( t1_id INT PRIMARY KEY AUTO_INCREMENT )" )
cursor.commit()
cursor.execute( "CREATE TABLE t2 ( t2_id INT PRIMARY KEY AUTO_INCREMENT )" )
cursor.commit()

На мой взгляд, это серьезная, вопиющая ошибка проектирования DB-API Python, из-за которой возникают серьезные проблемы с выполнением команд вне транзакций и надлежащим контролем над транзакциями, например. использовать такие вещи, как SQLiteBEGIN EXCLUSIVE TRANSACTION, Как будто кому-то, у которого нет опыта работы с базами данных, было разрешено разрабатывать API ...

 Glenn Maynard17 янв. 2011 г., 03:15
@singularity: Нет, вы упускаете суть. Вы не запускаете каждую операцию в отдельной транзакции; смысл в том, чтобы позволить пользователю запускать и фиксировать транзакции самостоятельно, как и должно быть, включая возможность задавать параметрыBEGIN TRANSACTION и возможность запуска команд вне любой транзакции (например, Postgresql'sVACUUM команда не может быть использована внутри транзакции). API не должен пытаться магически абстрагировать удаленные транзакции; это следует оставить пользователю. Вы можете отключить это поведение с помощью автоматической фиксации, но опять же, это нарушает код, который не ожидает его.
 mouad16 янв. 2011 г., 23:37
@ Гленн Мейнард: нет, это не так, это просто позволитавтокоммит опция для соединения курсора, которую мы создали в нашем коде :), включение автоматической фиксации может быть очень полезным в некоторых случаях, когда мы хотим сэкономить в реальном времени, а не делать это каждый разcursor.commit() ...
 Glenn Maynard16 янв. 2011 г., 23:14
@singularity: Но если вы сделаете это, вы измените поведение API на низком уровне - это может укусить вас, например, если вы передаете соединение стороннему коду.
 Glenn Maynard16 янв. 2011 г., 23:44
@singularity: Это так: он заставляет API больше не переносить блоки команд в транзакции, и этот код теперь зависит от поведения DB-API по умолчанию.
 mouad16 янв. 2011 г., 22:32
+1, или вы можете просто установитьавтокоммит во-первых, к значению true, которое по умолчанию отключено; нравитсяcursor.connection.autocommit(True).

Ваш ответ на вопрос