当我不调用conn.commit()时,为什么提交了我的SQL Server表条目?

时间:2019-09-19 15:01:30

标签: python sql-server odbc pyodbc

我很好奇为什么我的数据被提交到服务器,因为据我了解,当通过pyodbc向SQL Server写行时,必须先调用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 个答案:

答案 0 :(得分:1)

就像Pyodbc documentation对于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

答案 1 :(得分:0)

如果您需要自己控制交易,则既需要开始交易又要提交/回退。否则,它将不在显式事务模式下,并且SQL Server将每个命令视为一个事务并提交。