CakePHP 中的数据并发管理 - 行为/控制器/模型


Data concurrency management in CakePHP - Behavior / Controller / Model?

为了管理并发性 - 即确保保存到数据库的数据不会过时或已被其他用户编辑 - 在我的CakePHP应用程序中,我在编辑函数中使用modified属性。下面是我的控制器中的代码片段。

$this->MyModel->recursive = -1;
$event = $this->MyModel->findById($id);
$requestTimeStamp = new DateTime($this->request->data['MyModel']['modified']);
$dbTimeStamp = new DateTime($event['MyModel']['modified']);
if ($requestTimeStamp < $dbTimeStamp) {
    $response = array(
         'success' => false, 
         'id' => $id, 
         'message' => 'A concurrency error occurred while trying to save. Please try again');
    echo json_encode($response);
    exit;
} else {
   //... continue processing
}

这段代码工作正常 - 但是当我尝试在整个应用程序中优化它时,我试图找出放置它的最佳位置。它是最好放在我的AppModel类中,还是最好为相同的类创建一个Behavior,或者最好将其保留在控制器中?我想一个理想的选择是考虑性能并最大限度地减少类加载开销以及数据库访问开销。

以前有没有人遇到/解决这个问题?感谢想法/建议。

因此,我通过将并发检查作为AppModel->beforeSave()方法的一部分来解决此问题。以下是代码供他人参考

/*
 * Incorporated concurrency check in the beforeSave callback method to ensure that data is not stale before user saves.
 * The function checks if the model has a `modified` field, before it proceeds. If the model does not have such a method
 * then concurrency does not apply to this data structure. Upon proceeding, the method checks to see if the value of modified
 * data is the same in the database as well as the request that invokes this method. If they are not same then the save is 
 * aborted
 * This method requires the view or controller to pass a variable called data[ModelName][modified]. 
 * This variable must contain the value of the modified field when the record was read and it must be passed back as such. 
 * I usually set a hidden form field in my view like below - 
 * <input type="hidden" name="data[Model][modified]" value="<?php echo $model['modifed']; ?>" />
 */
    public function beforeSave($options = array()) {
        if ($this->hasField('modified') && isset($this->data[$this->name]['id']) && isset($this->data[$this->name]['modified'])) {
            CakeLog::debug('AppModel: beforeSave - inside concurrency check');
            CakeLog::debug($this->data);
            $this->recursive = -1;
            // run a select statement to ensure the modified date in the database has not changed. If it has changed then 
            // the below find query will return 0 rows
            $row = $this->find('first', array(
                'fields' => array(
                    'id', 'modified'
                ),
                'conditions' => array(
                    'id' => $this->data[$this->name]['id'],
                    'modified' => $this->data[$this->name]['modified']
                )
            ));
            // if no row is returned then error out and return - basically a concurrency error has occurred
            if (!$row) {
                CakeLog::error($this->name.':Concurrency error - [row-id:'.$this->data[$this->name]['id'].']');
                return false;
            }
            // if a row was retrned then there is no concurrency error, so proceed but change the modified date
            // to current timestamp to reflect accuracy
            $this->data[$this->name]['modified'] = date('Y-m-d H:i:s');
            return true;
        }
    }