Почему моя запись в таблицу SQL Server была зафиксирована, когда я не вызывал conn.commit ()? - PullRequest
0 голосов
/ 19 сентября 2019

Мне любопытно, почему мои данные были переданы на сервер, так как я понимаю, что при записи строк в SQL Server через pyodbc вы должны сначала вызвать connection.commit(), прежде чем данные будут переданы на сервер.Однако, когда я запускаю приведенный ниже код без использования commit(), данные все еще передаются в мою таблицу, что подтверждается:

cursor.execute("SELECT * FROM db.table")
tables = cursor.fetchall()

, а также проверкой таблицы вручную через SSMS.

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

import pyodbc


row_string = 'FIRST_NAME, LAST_NAME, MEMBER_EMAIL, SUPERVISOR_NAME, SUPERVISOR_EMAIL, MEMBER_TITLE'
value_string = [['Name', 'LName', 'Name.LName@randome.com', 'Super Name',
                'Super.Name@random.com', 'Some Title']]
ex_value = "insert into DB.TABLE ({}) values (?, ?, ?, ?, ?, ?)".format(row_string)
print(ex_value)

odbc_driver, server, db = '{ODBC Driver 17 for SQL Server}', 'server_address', 'dbname'

# I did try to use this try/except statement provided by Chiheb Nexus below.
# Oddly enough this committed the data but my print statement did not execute.

with pyodbc.connect(driver=odbc_driver, host=server, database=db, trusted_connection='yes') as conn:
    try:
        conn.autocommit = False
        cursor = conn.cursor()
        cursor.executemany(ex_value, value_string)
        cursor.execute("SELECT * FROM db.TABLE")
        tables = cursor.fetchall()

        for row in tables:
            print('Row: {}'.format(row))

    except pyodbc.DatabaseError as err:
        conn.rollback()
    else:
        conn.commit()
    finally:
        conn.autocommit = True

    cursor.close()

Полученные данные:

insert into db.TABLE (FIRST_NAME, LAST_NAME, MEMBER_EMAIL, SUPERVISOR_NAME, SUPERVISOR_EMAIL, MEMBER_TITLE) values (?, ?, ?, ?, ?, ?)
Row: (9002, 'Name', 'LName', 'Name.LName@randome.com', 'Super Name', 'Super.Name@random.com', 'Some Title', 'None')
Row: (9001, 'Name1 ', 'LName1', 'Name1.LName1@random.com', 'Super Name', 'Super.Name@random.com', 'Some Title', 'None')

Дополнительный вопрос, еслиКто-нибудь знает (не странная проблема), почему мои данные представлены в обратном порядке.Я ожидал, что мои данные будут упорядочены сверху вниз, как в записи 9001 за 9002, а не наоборот, как это показано выше.

Ответы [ 2 ]

1 голос
/ 19 сентября 2019

Как и то, что Документация Pyodbc говорит в случае executemany функции:

Также будьте осторожны, если autocommit имеет значение True.В этом случае предоставленный оператор SQL будет зафиксирован для каждой записи в последовательности параметров.Таким образом, если ошибка происходит в процессе обработки, в результате вы получите некоторые записи, зафиксированные в базе данных, а остальные нет, и может быть нелегко определить, какие записи были зафиксированы.Следовательно, вы можете захотеть установить для параметра autocommit значение False (и явно commit () / rollback ()), чтобы убедиться, что либо все записи зафиксированы в базе данных, либо отсутствуют

Итак, вам нужнодобавьте conn.autocommit = False перед cursor.executemany и явно добавьте conn.commit() и conn.rollback(), в противном случае ваши изменения будут зафиксированы в вашей БД.

А вот пример из документа:

try:
    cnxn.autocommit = False
    params = [ ('A', 1), ('B', 2) ]
    cursor.executemany("insert into t(name, id) values (?, ?)", params)
except pyodbc.DatabaseError as err:
    cnxn.rollback()
else:
    cnxn.commit()
finally:
    cnxn.autocommit = True
0 голосов
/ 19 сентября 2019

Если вам нужно контролировать транзакцию самостоятельно, вам нужно как начать транзакцию, так и зафиксировать / откатить.В противном случае он НЕ находится в режиме явной транзакции, и сервер SQL принимает каждую команду как одну транзакцию и фиксирует ее.

...