Мы уже давно используем TreeBehavior с CakePHP 3.6. В последнее время с большим деревом (около 90000 узлов) мы сталкиваемся с проблемами.
При удалении узла функция beforeDelete () вызывается в cakephp / src / ORM / Behavior / TreeBehavior:
/**
* Also deletes the nodes in the subtree of the entity to be delete
*
* @param \Cake\Event\Event $event The beforeDelete event that was fired
* @param \Cake\Datasource\EntityInterface $entity The entity that is going to be saved
* @return void
*/
public function beforeDelete(Event $event, EntityInterface $entity)
{
$config = $this->getConfig();
$this->_ensureFields($entity);
$left = $entity->get($config['left']);
$right = $entity->get($config['right']);
$diff = $right - $left + 1;
if ($diff > 2) {
$query = $this->_scope($this->_table->query())
->delete()
->where(function ($exp) use ($config, $left, $right) {
/* @var \Cake\Database\Expression\QueryExpression $exp */
return $exp
->gte($config['leftField'], $left + 1)
->lte($config['leftField'], $right - 1);
});
$statement = $query->execute();
$statement->closeCursor();
}
$this->_sync($diff, '-', "> {$right}");
}
Эта функция вызывает функцию _sync () для обновления левого и правого значений дерева:
/**
* Auxiliary function used to automatically alter the value of both the left and
* right columns by a certain amount that match the passed conditions
*
* @param int $shift the value to use for operating the left and right columns
* @param string $dir The operator to use for shifting the value (+/-)
* @param string $conditions a SQL snipped to be used for comparing left or right
* against it.
* @param bool $mark whether to mark the updated values so that they can not be
* modified by future calls to this function.
* @return void
*/
protected function _sync($shift, $dir, $conditions, $mark = false)
{
$config = $this->_config;
foreach ([$config['leftField'], $config['rightField']] as $field) {
$query = $this->_scope($this->_table->query());
$exp = $query->newExpr();
$movement = clone $exp;
$movement->add($field)->add((string)$shift)->setConjunction($dir);
$inverse = clone $exp;
$movement = $mark ?
$inverse->add($movement)->setConjunction('*')->add('-1') :
$movement;
$where = clone $exp;
$where->add($field)->add($conditions)->setConjunction('');
$query->update()
->set($exp->eq($field, $movement))
->where($where);
$query->execute()->closeCursor();
}
}
Однако кажется, что запросы на обновление, выполняемые этой функцией _sync (), не являютсязаключены в транзакцию и выглядят следующим образом:
UPDATE `leafs` SET `lft` = ((`lft` - 12)) WHERE ((`lft` > 52044))
UPDATE `leafs` SET `rght` = ((`rght` - 12)) WHERE ((`rght` > 52044))
Разве они не должны быть заключены в транзакцию, как это?
START TRANSACTION
UPDATE `leafs` SET `lft` = ((`lft` - 12)) WHERE ((`lft` > 52044))
UPDATE `leafs` SET `rght` = ((`rght` - 12)) WHERE ((`rght` > 52044))
COMMIT
... особенно, если обновляются значения(левый и правый) также встречаются в предложении WHERE. У нас есть некоторые проблемы с повреждением дерева, и мы задаемся вопросом, может ли это быть причиной ... особенно, когда на большом дереве выполняется несколько последовательных операций.