Python 如何更新事务中的对象属性更改?

Python 如何更新事务中的对象属性更改?,python,oop,asynchronous,concurrency,python-asyncio,Python,Oop,Asynchronous,Concurrency,Python Asyncio,我正在设计一个应用程序,在那里我们对客户记录执行操作,例如我们可以更新他们的余额,添加他们购买的物品或给他们提供的服务等。我希望每个操作在本质上都是原子的 应用程序是用Python编写的,但我试图解决的问题是语言不可知的 现在,我有多个异步函数,它们同时运行,可以更新客户记录。但是我只想在一切正常并且没有抛出异常的情况下更新客户记录。并在引发异常时恢复 为了确保只有一个函数可以更新客户,我在客户记录上有一个锁,目前只有一个异步函数可以获取。客户记录是可变类型的,因此可以通过功能进行更新 clas

我正在设计一个应用程序,在那里我们对客户记录执行操作,例如我们可以更新他们的余额,添加他们购买的物品或给他们提供的服务等。我希望每个操作在本质上都是原子的

应用程序是用Python编写的,但我试图解决的问题是语言不可知的

现在,我有多个异步函数,它们同时运行,可以更新客户记录。但是我只想在一切正常并且没有抛出异常的情况下更新客户记录。并在引发异常时恢复

为了确保只有一个函数可以更新客户,我在客户记录上有一个锁,目前只有一个异步函数可以获取。客户记录是可变类型的,因此可以通过功能进行更新

class Customer:
  def __init__(self, name, balance, items):
     self.name = name
     self.balance = balance
     self.items = items
     self.lock = asyncio.Lock()


class Handler:

   async def handle(customer, type, data):

      async with customer.lock:
        try:
         #all functions that update customer properties
          
          if type == 'updatebalance' : 
             UpdateCustomerBalance(customer, data)
          else:
             UpdateCustomerItems(customer, data) 

        except Exception as ex:
          #how do I revert customer changes? 
          pass
在上面的代码中,我有一个customer类。它几乎没有属性和锁

每当调用handler时,它都会获取客户的锁。它调用获取数据并更新客户属性的其他函数

Customer是一个引用类型,由这些函数进行变异,例如一个函数可以更新余额。如果捕获到异常,则我希望恢复更改

当我异步多次运行调用句柄时,我希望确保将相同的客户记录发送到函数,以便成功的更改保存在客户记录中,并且我们不会丢失更改,例如一个句柄调用可以添加项,第二个句柄调用可以删除该项

简而言之,我想要一个交易机制。这可能吗?我是否应该在内部深度克隆customer对象并将其传递给函数?但是,我必须手动更新更改的属性,以便下一个调用能够在更新的对象上工作


实现事务的正确方法是什么?

您可以使
Customer
对象不可变,并通过替换整个对象来更改状态。此方法不需要任何事务,因为所有更改都将减少为单个替换

e、 g

customer_store={}
类处理程序:
异步def句柄(自身、客户、类型、数据):
#为任何更新创建新客户
当前客户=客户商店[customer.key]
如果类型=='updatebalance':
new_customer=UpdateCustomerBalance(当前_客户,数据)
其他:
新客户=更新的客户项(当前客户,数据)
#替代品
customer\u store[customer.key]=新客户

另外,
handle
在等待某些东西之前不需要锁。

实现事务的“正确方法”是尽可能不使用锁。事务具有棘手的边缘情况,因此如果您可以改变它,那么重新使用其他人的工作会更好。您是否可以将问题重新定义为数据库问题,并使用数据库操作而不是对象突变?如果您不等待
async with
块中的任何内容,则不需要任何锁定,因为从一开始一切都是原子的。恢复在任意对象上执行的更改并在其间的任何位置引发异常是一个极其困难的问题。正如前面的评论所说,不要试图自己实现它。你能解释一下锁定部分吗?客户记录列表存储在一个字典中,我定期将其保存在数据库中。我有多个在后台运行的异步任务,用于侦听事件并对客户执行操作。其中一些行动是从外部网站(如亚马逊)购买产品。当我从外部等待handle函数时,这些函数都不会等待。你是说我不需要锁?另外,我不能在每次操作后使用数据库,因为这是一个高流量的应用程序,所以锁确保以正确的顺序调用handle函数。例如,如果我收到两个handle请求,一个请求在客户余额中添加资金,另一个请求删除客户余额,那么在添加之前我不会先删除余额。因此,我的理解是,当通过asyncio.create_任务异步调用handle coutroutine时,锁将提供排序功能,你是说我不需要锁吗?-是的,我是说,如果你不等待任何事情,你不需要锁,因为它不会完成任何事情。异步IO多任务处理是协作的,如果您不等待,就无法切换到其他任务,因此锁定是多余的。至于排序,锁是公平的,并且将尊重尝试获取它的顺序,但是没有锁,您将获得相同的效果,因为asyncio不能同时运行两件事情。在考虑这个问题时,请始终记住asyncio是单线程的。如果我在函数中使用Wait,并且如果我的客户是可变引用类型,那么在所有任务中不是只有一个版本的客户吗?我正在努力等待和锁定。因此,对于您的设计,下一次对句柄的调用(已经在队列中)将丢失此句柄调用将进行的更改。所有任务中不是只有一个版本的客户吗?-对不起,我不清楚这个问题。你所说的一个版本的客户是什么意思?如果您指的是同一个客户对象,那么答案是否定的,它们可能是不同的对象如果您在函数中使用wait,那么您将必须锁定一个客户对象,因为wait可能会将执行切换到另一个可能尝试访问同一个客户对象的任务。下一个已在队列中的处理调用将丢失更改。如果假定同时执行
句柄
,就会发生这种情况。在这种情况下,您可以从函数中的
Customer\u store
获取客户对象。我更新了答案