考慮以下幾點:是否Zend_Db_Adapter :: beginTransaction()堆棧?
/** (Cas_Template_Tree::DeleteNode)
* Deletes the given node from the tree, and all of it's children.
*
* @static
* @throws Exception
* @param Cas_Template_Node $node
* @return void
*/
public static function DeleteNode(Cas_Template_Node $node)
{
$table = new Cas_Table_Templates();
$adapter = $table->getAdapter();
$leftStr = $adapter->quoteIdentifier('Left');
$rightStr = $adapter->quoteIdentifier('Right');
try
{
$adapter->beginTransaction();
$row = $table->find($node->GetId())->current();
$dependantRowSelector = array(
"$leftStr >= ?" => $row->Left,
"$rightStr <= ?" => $row->Right
);
//Get the rows removed so that we can nuke the ACLs later.
$rowsToDelete = $table->fetchAll($dependantRowSelector)->toArray();
//Delete the rows.
$table->delete($dependantRowSelector);
//Delete access control lists on those rows.
foreach ($rowsToDelete as $rowToDelete)
{
Cas_Acl::CreateExisting($rowToDelete['Acl'])->Delete();
}
$left = (int)$row->Left;
$right = (int)$row->Right;
$difference = $right - $left + 1;
$table->update(array('Left' => new Zend_Db_Expr("$leftStr - $difference")),
array("$leftStr > ?" => $right));
$table->update(array('Right' => new Zend_Db_Expr("$rightStr - $difference")),
array("$rightStr > ?" => $right));
$adapter->commit();
}
catch (Exception $ex)
{
$adapter->rollBack();
throw $ex;
}
}
/** (Cas_Acl::Delete)
* Removes this ACL (and all of its dependent access control entries) from the database.
* @return void
*/
public function Delete()
{
$aclTable = new Cas_Table_AccessControlLists();
$aceTable = new Cas_Table_AccessControlEntries();
$adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
$identifierName = $adapter->quoteIdentifier('Identifier');
$aclName = $adapter->quoteIdentifier('Acl');
try
{
$adapter->beginTransaction();
$aceTable->delete(array("$aclName = ?" => $this->GetId()));
$aclTable->delete(array("$identifierName = ?" => $this->GetId()));
}
catch (Exception $ex)
{
$adapter->rollBack();
throw $ex;
}
}
注意這兩個是如何要求的交易工作,因爲否則操作不會是原子(這將是壞的;))然而,有兩個交易模塊怎麼回事。原始的DeleteNode方法調用Cas_Acl::Delete()
,它也嘗試在事務塊內執行自己。理想情況下,Zend_Db足夠聰明以識別這種情況,對於這個特定的調用忽略Cas_Acl::Delete
內的開始事務和提交/回滾調用。
上面的代碼是否安全?它能以任何方式顯着改善嗎?
你有時直接調用Delete()嗎?還是隻在`DeleteNode()`中調用? – singles 2011-02-08 07:22:32
@singles:是 - 只要需要刪除ACL,就會調用「Cas_Acl :: Delete」。還有一個ACL附加到這個應用程序管理的大多數對象。其中一些對象使用交易,而另一些則不需要。 – 2011-02-08 08:38:14
你的代碼提出了我的問題,就像tintin http://omg.wthax.org/haddock.jpg中的haddock的鬍子一樣,我認爲「$ adapter-> beginTransaction();」應該在「try {} catch」之前設置,而不是在 – regilero 2011-02-08 12:49:46