1

鉴于 QLDB 公开的有限driver接口,如何将存储库 + 工作单元模式与 QLDB 一起使用?我正在使用pyqldb图书馆。遵循我从( https://www.cosmicpython.com/book/preface.html,他们使用)学习模式的宇宙 Python 书SQLAlchemy,这是我迄今为止提出的:

class AbstractRepo(abc.ABC):
    @abc.abstractmethod
    def add(self, thing: Thing) -> None:
        raise NotImplementedError

    @abc.abstractmethod
    def get(self, id: str) -> Optional[Thing]:
        raise NotImplementedError

class QldbRepo(AbstractRepo):
    def __init__(self, tx_executor: executor.Executor):
        self.executor = tx_executor  # Should this be driver?
        
    def add(self, thing: Thing) -> None:
        self.executor.execute_statement("INSERT INTO things ...")

    def get(self, id: str) -> Optional[Thing]:
        return self.executor.execute_statement("SELECT * FROM things ...")

class AbstractUnitOfWork(abc.ABC):
    ...

class QldbUnitOfWork(AbstractUnitOfWork):
    def __init__(self, driver: qldb_driver.QldbDriver):
        self.things = QldbRepo(<how do I pass in the executor? Or should this be driver?>)
        self.driver = driver

    def __enter__(self) -> None:
        ...

    def __exit__(self) -> None:
        ...

    def commit(self) -> None:
        self.driver.execute_lambda(lambda executor: <what goes in here?>)

# In services, it would be used like this
def add_thing(id: str) -> None:
    with uow:
        thing = uow.things.get(id)
        if not thing:
            thing = Thing(...)
            uow.things.add(thing)
        uow.commit()
    

在上面的代码中,Thing是聚合的聚合根。聚合中还有其他对象。

所以具体的问题是:

  1. 回购应该tx_executor作为依赖还是driver?如果是前者,我如何给它一个执行人?
  2. 应该QldbRepo.add实际执行该INSERT语句,或者 repo 是否应该维护一个简单的内存数据结构(例如Things 列表)并将新的添加thing到该结构中,然后commit将弄清楚如何进行插入?
  3. 应该如何get实施?如果我这样做driver.execute_lambda(...),则意味着inget和以下addinadd_thing不再在单个事务中,因此我不会获得事务保证并且可能会遇到并发问题,对吗?
  4. 应该如何UnitOfWork.commit实施?具体来说,如何将所有内容包装到 lambda 函数中并将其传递给commit

任何帮助将不胜感激。谢谢!


更新:

我刚刚想到的一种潜在解决方案可以解决以下问题add

  1. QldbRepo维护一个名为 的 lambda 列表instructions,每个 lambda 对应于 repo 的调用者调用的命令 - 在这种情况下,每次QldbRepo.add调用时,我们都会执行 `instructions.append(lambda executor: executor.execute_statement("INSERT INTO ...”))。
  2. UnitofWork.commit()中,读取 repo 维护的 lambda 列表,并一一执行。请参阅下面的代码。
class QldbRepo(AbstractRepo):
    def __init__(self):
        self.instructions = []
        
    def add(self, thing: Thing) -> None:
        self.instructions.append(lambda executor: executor.execute_statement("INSERT INTO ..."))

class QldbUnitOfWork(AbstractUnitOfWork):
    def __init__(self, driver: qldb_driver.QldbDriver):
        self.things = QldbRepo()
        self.driver = driver
        self.state = "NEW"

    def __enter__(self) -> None:
        self.state = "STARTED"

    def __exit__(self) -> None:
        self.state = "NEW"

    def commit(self) -> None:
        if self.state != "STARTED"
            raise Exception
        
        def _commit(executor) -> None:
            for instruction in things.instructions.pop(0):
                instruction(executor)
        self.driver.execute_lambda(_commit)
        self.state = "NEW"

这有意义吗?还是不知道怎么处理get。也许它必须在一个单独的事务中,我们会通过version_number在模型上添加一个变量来解决并发问题Thing

4

0 回答 0