【问题标题】:How database Transaction work with application code数据库事务如何与应用程序代码一起使用
【发布时间】:2015-09-01 13:00:28
【问题描述】:

假设我们有以下伪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()

我知道事务将提供一个“全有或全无”的命题,但不知道如果与应用程序代码混合它是如何工作的。数据库事务如何处理应用代码如:if result['count'] == 1.

据我了解,当提交时,所有的 sql 都会被处理到数据库服务器执行,服务器会确保 sql 执行“all-or-nothing”。但是上面的代码应该只在count等于1时执行UPDATE sql。如果所有 sql 都已经处理到数据库服务器并且其他一些事务只是更改了count,会发生什么?

【问题讨论】:

标签: python mysql sql transactions


【解决方案1】:

事务包括对数据库所做的任何更改。如果应用程序代码测试阻止进行更改,则它们不是事务的一部分。因此,如果result['count'] 不等于1,则不会进行任何更改,因为您从未将UPDATE 命令发送到数据库。

将事务视为您交给数据库的“待办事项列表”,commit 告诉数据库执行该列表。您的if 测试只是控制您是否在该列表上写下更新。数据库不必关心您是如何编写列表的。

如果您正在寻找防止UPDATE 发生的方法,如果另一个事务也同时更新了数据库,那么您需要研究锁定策略(创建一个独占的lock 以强制整个事务以一系列方式发生)或使用乐观锁定检测在事务期间该行已被更改。见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;毕竟,我们选择的是count=1。

【讨论】:

  • @realli:为了什么目的?即使您将其移至数据库存储过程,您也不会受到其他事务冲突的保护。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-21
  • 2012-02-24
相关资源
最近更新 更多