鉴于 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
是聚合的聚合根。聚合中还有其他对象。
所以具体的问题是:
- 回购应该
tx_executor
作为依赖还是driver
?如果是前者,我如何给它一个执行人? - 应该
QldbRepo.add
实际执行该INSERT
语句,或者 repo 是否应该维护一个简单的内存数据结构(例如Thing
s 列表)并将新的添加thing
到该结构中,然后commit
将弄清楚如何进行插入? - 应该如何
get
实施?如果我这样做driver.execute_lambda(...)
,则意味着inget
和以下add
inadd_thing
不再在单个事务中,因此我不会获得事务保证并且可能会遇到并发问题,对吗? - 应该如何
UnitOfWork.commit
实施?具体来说,如何将所有内容包装到 lambda 函数中并将其传递给commit
?
任何帮助将不胜感激。谢谢!
更新:
我刚刚想到的一种潜在解决方案可以解决以下问题add
:
QldbRepo
维护一个名为 的 lambda 列表instructions
,每个 lambda 对应于 repo 的调用者调用的命令 - 在这种情况下,每次QldbRepo.add
调用时,我们都会执行 `instructions.append(lambda executor: executor.execute_statement("INSERT INTO ...”))。- 在
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
?