如何修改下面的代码以确保两个删除都将在CakePHP 3.x中的一个事务中进行?
// In initialize:
$this->loadModel('A');
// In the delete function:
$elem=$this->A->get($id);
$rec=$elem->...;
$this->A->delete($elem);
$this->loadModel('B');
$this->B->deleteAll(['B.rec'=>$rec]);
答案 0 :(得分:2)
如果您的表彼此关联,您可以使用dependent
选项来定义自动删除相关记录的关联。默认情况下,这将发生在事务中。
$this->hasMany('B', [
'dependent' => true,
// ...
]);
另见
这就是\Cake\Datasource\ConnectionInterface::transactional()
方法,分别是\Cake\Database\Connection::begin()
,commit()
和rollback()
方法。
使用transactional()
是一种更简单的方法,在传递的回调中完成的所有操作都在事务中运行。
来自文档的引用:
交易方法将执行以下操作:
- 致电
begin
。- 调用提供的闭包。
- 如果闭包引发异常,则会发出回滚。将重新抛出原始异常。
- 如果闭包返回
false
,则会发出回滚。- 如果闭包执行成功,将提交交易。
<强>返回强>
mixed
回调的返回值。
因此,将代码包装在回调中,并确保评估Table::delete()
返回值并在必要时返回false
,以便在删除操作失败时发出回滚。 / p>
$connection = \Cake\Datasource\ConnectionManager::get('default');
$result = $connection->transactional(function ($connection) use ($id) {
$elem = $this->A->get($id);
$rec = $elem->/*...*/;
if (!$this->A->delete($elem, ['atomic' => false])) {
return false;
}
$this->loadModel('B');
$this->B->deleteAll(['B.rec' => $rec]);
return true;
});
请注意,在这种情况下应禁用atomic
选项,以便delete()
不会尝试自行创建事务。
还应该注意的是,如果您的代码需要触发该事件,那么手动将delete()
调用内部事务会导致Model.afterDeleteCommit
事件不被触发那么你必须自己做。
另见
答案 1 :(得分:0)
$this->Model->hasMany('TrModels', [ 'bindingKey' => 'transaction column', 'foreignKey' => 'transaction column', 'joinType' => 'LEFT', 'dependent' => true, 'cascadeCallbacks' => true,]);
$deleteINQ = $this->Models->get($id);//Parrent id
$this->Models->delete($deleteINQ);