数据库事务如何与应用程序代码一起工作
How database Transaction work with application code
假设我们有以下伪 python 代码来处理 Mysql:
with connection.cursor() as cursor:
sql = "SELECT `count` FROM `sometable` WHERE `name`=%s"
cursor.execute(sql, ('somename',))
result = cursor.fetchone()
if result['count'] == 1:
sql = "UPDATE `sometable` SET `count`=%d WHERE `name`=%s"
cursor.execute(sql, (10, 'somename'))
connection.commit()
我知道事务将提供一个 "all-or-nothing" 命题,但不知道如果与应用程序代码混合它是如何工作的。数据库事务如何处理应用程序代码,如:if result['count'] == 1
.
在我的理解中,提交时,所有sqls 将被处理到数据库服务器执行,服务器将确保sqls 执行"all-or-nothing"。但是上面的代码应该只在 count
等于 1
时执行 UPDATE
sql。如果所有 sql 都已处理到数据库服务器并且其他一些事务只是更改 count
会发生什么?
事务包括对数据库所做的任何更改。如果应用程序代码测试阻止进行更改,则它们不是事务的一部分。因此,如果 result['count']
不等于 1
,则没有进行任何更改,因为您从未向数据库发送 UPDATE
命令。
将事务视为 'todo list' 您交给数据库,然后 commit
告诉数据库去执行该列表。您的 if
测试只是控制您是否在该列表上写下更新。数据库不必关心你是如何写列表的。
如果您正在寻找方法来防止 UPDATE
在另一个事务也并行更新数据库 时发生,那么您需要看看进入锁定策略(创建排他锁以强制整个事务在一个系列中发生)或检测该行在具有乐观锁定的事务期间已被更改。参见 Do database transactions prevent race conditions?。
对于你的具体情况,后者看起来像这样:
with connection.cursor() as cursor:
sql = "SELECT `count` FROM `sometable` WHERE `name`=%s"
cursor.execute(sql, ('somename',))
result = cursor.fetchone()
if result['count'] == 1:
sql = "UPDATE `sometable` SET `count`=%d WHERE `name`=%s and `count`=1"
cursor.execute(sql, (10, 'somename'))
if cursor.rowcount != 1:
# another transaction updated the row already. Handle this gracefully.
# you could elect to roll back here.
如果具有匹配 name
列的行已更改为具有不同的 count
值,则 UPDATE
之后的 rowcount
将为 0;毕竟,我们选择的是 <code>count
=1。
假设我们有以下伪 python 代码来处理 Mysql:
with connection.cursor() as cursor:
sql = "SELECT `count` FROM `sometable` WHERE `name`=%s"
cursor.execute(sql, ('somename',))
result = cursor.fetchone()
if result['count'] == 1:
sql = "UPDATE `sometable` SET `count`=%d WHERE `name`=%s"
cursor.execute(sql, (10, 'somename'))
connection.commit()
我知道事务将提供一个 "all-or-nothing" 命题,但不知道如果与应用程序代码混合它是如何工作的。数据库事务如何处理应用程序代码,如:if result['count'] == 1
.
在我的理解中,提交时,所有sqls 将被处理到数据库服务器执行,服务器将确保sqls 执行"all-or-nothing"。但是上面的代码应该只在 count
等于 1
时执行 UPDATE
sql。如果所有 sql 都已处理到数据库服务器并且其他一些事务只是更改 count
会发生什么?
事务包括对数据库所做的任何更改。如果应用程序代码测试阻止进行更改,则它们不是事务的一部分。因此,如果 result['count']
不等于 1
,则没有进行任何更改,因为您从未向数据库发送 UPDATE
命令。
将事务视为 'todo list' 您交给数据库,然后 commit
告诉数据库去执行该列表。您的 if
测试只是控制您是否在该列表上写下更新。数据库不必关心你是如何写列表的。
如果您正在寻找方法来防止 UPDATE
在另一个事务也并行更新数据库 时发生,那么您需要看看进入锁定策略(创建排他锁以强制整个事务在一个系列中发生)或检测该行在具有乐观锁定的事务期间已被更改。参见 Do database transactions prevent race conditions?。
对于你的具体情况,后者看起来像这样:
with connection.cursor() as cursor:
sql = "SELECT `count` FROM `sometable` WHERE `name`=%s"
cursor.execute(sql, ('somename',))
result = cursor.fetchone()
if result['count'] == 1:
sql = "UPDATE `sometable` SET `count`=%d WHERE `name`=%s and `count`=1"
cursor.execute(sql, (10, 'somename'))
if cursor.rowcount != 1:
# another transaction updated the row already. Handle this gracefully.
# you could elect to roll back here.
如果具有匹配 name
列的行已更改为具有不同的 count
值,则 UPDATE
之后的 rowcount
将为 0;毕竟,我们选择的是 <code>count
=1。