在不同游标/连接中使用BEGIN TRANSACTION / ROLLBACK / COMMIT
我想知道在使用不同的游标或连接时,事务是如何运作的,比如开始事务、提交等命令。也就是说,下面这些语句中,哪一组实际上会引入一个单一的事务,并在最后提交它呢?
connection = pyodbc.connect(...)
cursor = connection.cursor()
cursor.execute('START TRANSACTION')
cursor.execute('INSERT ....')
cursor.execute('COMMIT')
与之相比。
connection = pyodbc.connect(...)
connection.cursor().execute('START TRANSACTION')
connection.cursor().execute('INSERT ....')
connection.cursor().execute('COMMIT')
再与这个比较。
pyodbc.connect(...).cursor().execute('START TRANSACTION')
pyodbc.connect(...).cursor().execute('INSERT ....')
pyodbc.connect(...).cursor().execute('COMMIT')
(实际上,这些命令分散在我的代码中,我正在尝试弄清楚在哪些层级引入单例模式)
当然,我可以通过“尝试”来找出一些答案,但我更希望能得到一个更权威的回答,这样我就知道一周后不会出问题。
我使用的是Python的数据库API,不过我想这个问题不一定只和Python有关。我能想象(虽然我希望不是这样)这个问题可能和数据库有关。顺便提一下:我们使用的是MsSQL Server 2000。
2 个回答
我对pyodbc不是很确定——我想这可能跟你连接的具体数据库引擎有关。不幸的是,很多实现了DB API 2.0的模块在文档中并没有明确说明事务是跟连接还是跟游标(cursor)相关的,DB API 2.0的规范本身也没有说明这个问题(http://legacy.python.org/dev/peps/pep-0249/)。
不过,有几个数据库的事务是包括在单个连接上所有游标执行的所有语句的(这意味着你给出的第一个和第二个例子都会有效)。例如,psycopg2的文档明确指出:
[D]atabase命令将在同一个事务的上下文中执行——不仅是第一个游标发出的命令,还有所有由同一个连接创建的游标发出的命令。
(在http://initd.org/psycopg/docs/usage.html的“事务控制”部分)
同样,MySQL不支持游标——它们是在Python层面上模拟的,所以从定义上来说,一个事务包含了整个连接的级别,而不仅仅是单个游标。
到目前为止,我想到的办法是通过使用Python的数据库API的事务方法在连接上来绕过我自己的问题,而不是为它们创建游标。我还没有彻底测试过这个方法,一旦测试完毕,我会在这里分享我的答案。
也就是说:
connection = pyodbc.connect(...)
connection.begin() # superfluous, but for illustration purposes;
cursor = connection.cursor()
cursor.execute('INSERT ....')
connection.commit() # or rollback