我遇到的业务问题是:父实体有子实体的子实体。子实体有一个需要唯一的值,因此存在一个ChildLookup实体来强制实现该唯一性。为了抽象出一些东西,实体puts/deletes被放进了它们自己的方法中,并且都有批处理/事务语句作为它们逻辑的一部分。你知道吗
在Python中(使用this library),当结构如下时,一切正常:
# assuming ('Parent', 11), ('Parent', 11, 'Child', 'foo') (with value 'bar'), and ('ChildLookup-foo', 'bar') all exist
def put_parent(c):
p2 = c.get(c.key('Parent', 22))
if p2 is None:
p2 = Entity(c.key('Parent', 22))
c.put(p2)
def put_child(c):
with c.transaction():
e2 = Entity(c.key(*p2.key.flat_path, 'Child', 'foo'))
e2['__val'] = 'bar'
el2 = c.get(c.key('ChildLookup-foo', e2['__val']))
if el2 is not None:
raise ValueError('insert would create duplicate')
el2 = Entity(c.key('ChildLookup-foo', 'val'))
c.put(el2)
c.put(e2)
c = google.cloud.datastore.Client()
with c.transaction():
put_parent(c)
put_child(c)
尝试运行此命令将导致正确的行为:将引发异常,并且不会插入p2或e2。但是,我可以将put\ U parent更改为如下所示:
def put_parent():
with c.transaction(): # only actual change. can also be c.batch()
p2 = c.get(c.key('Parent', 22))
if p2 is None:
p2 = Entity(c.key('Parent', 22))
c.put(p2)
当我这样做时,p2被插入,尽管第二个事务正在回滚。这对我来说是出乎意料的:我希望回滚只限于最内部的事务(或批处理),或者我希望回滚影响最外部事务(或批处理)的所有子事务。你知道吗
当然,在上面这个简单的玩具示例中,我只需取出内部批并从顶层管理它。但将它们放入方法的意义在于,我可能偶尔希望单独调用它们,而不需要调用这两个方法的方法提供相同的保证,而且我希望它们的事务性要求对这些方法的使用者来说并不重要。有没有一个设计模式,或者一些Python-Google云数据存储库功能,可以让我做我想做的事情?你知道吗
编辑:
在接受答案的代码是下面的基础,我包括好奇。它最终产生了我想要的行为。你知道吗
from contextlib import contextmanager
@contextmanager
def use_existing_or_new_transaction(client):
if client.current_transaction:
yield client.current_transaction
else:
with client.transaction() as xact:
yield xact
@contextmanager
def use_existing_or_new_batch(client):
if client.current_transaction:
yield client.current_batch
else:
with client.batch() as xact:
yield xact
然后像这样使用
with use_existing_or_new_transaction(c) as xact:
xact.put(something)
xact.delete(something_else)
# etc
你试过c.U交易吗?你知道吗
https://googleapis.dev/python/datastore/latest/client.html
我们的想法是,你用
与c.事务()
在所有调用之外和每个调用内部,只需获取当前事务并使用它来执行操作。我认为您不应该在函数中使用'with',因为它将在最后自动提交/回滚。你知道吗
所以,应该是这样的。你知道吗
相关问题 更多 >
编程相关推荐