在 Yii 1.x 中,直接使用 DAO 的 delete() 方法極易因條件組裝錯誤導致「全表刪除」災難。本文說明風險所在,並推薦使用 ActiveRecord 的 deleteByAttributes()、deleteAll() 等更安全的方法,附帶多種條件寫法範例。
// 危險寫法:若條件組裝失敗,$condition 為空字串或陣列
Yii::app()->db->createCommand()
->delete('mw_user', $condition); // 可能產生 DELETE FROM mw_user (無 WHERE)
當條件變數為 null、空陣列、或組裝邏輯出錯時,DAO 不會拋出異常,而是生成無 WHERE 子句的 SQL,導致整張表資料清空。這類事故在生產環境極難恢復。
ActiveRecord 內建參數繫結與條件檢查,相對安全且可讀性高。
// 刪除 phone_number 等於 $phoneNumber 的所有記錄
MyClass::model()->deleteAllByAttributes(array(
'phone_number' => $phoneNumber,
));
// 第一參數為空陣列,第二參數用參數繫結寫條件
MyClass::model()->deleteAllByAttributes(array(), '`phone_number` = :phone_number', array(
':phone_number' => $phoneNumber,
));
MyClass::model()->deleteAll('`phone_number` = :phone_number', array(
':phone_number' => $phoneNumber,
));
$criteria = new CDbCriteria();
$criteria->addCondition('status = :status');
$criteria->params = array(':status' => 1);
$criteria->addInCondition('user_id', array(100111, 100221, 100331));
User::model()->deleteAll($criteria);
$condition = array('and', 'user_id = :user_id', array('in', 'position_id', array(1,2,3)));
$params = array(':user_id' => 121111);
// 防呆:確保條件非空
if (empty($condition)) {
throw new Exception('刪除條件不得為空');
}
Yii::app()->db->createCommand()
->delete('mw_user', $condition, $params);
| 場景 | 推薦方法 | 理由 |
|---|---|---|
| 單一/多欄位精確匹配刪除 | deleteAllByAttributes() | 參數化、防注入、語意清晰 |
| 複雜條件(範圍、IN、LIKE) | deleteAll($criteria) | 物件化條件、可重用、易維護 |
| 簡單字串條件 | deleteAll('sql', $params) | 輕量、直觀 |
| 批次/效能敏感操作 | DAO + 事務 + 防呆檢查 | 效能最佳,但需嚴格防禦 |
「慎用 DAO delete」不僅是口號,更是防止誤刪生產資料的鐵律。優先選用 ActiveRecord 封裝方法,把條件組裝交給框架,才能睡個安穩覺。