首页 > 解决方案 > 如何使用 MySQL 禁止 2 个用户在 Web 应用程序中编辑相同的数据(如果可能,使用 CodeIgniter)

问题描述

我在开发环境中使用 CodeIgniter 3 和 MariaDB 5.0(但在 prod 环境中使用 MySQL 5.6)。

我创建了一个 Web 应用程序,并实现了一个验证链来接受用户请求。

例如:

User A asked for something
The manager validate
The deputy validate
The commission validate
The accounting department validate
The request is accepted

这些验证在数据库中的几个表中注册。

我使用 SQL 事务通过 CodeIgniter 的函数和 CRUD 模型正确更新/插入数据,例如:

$this->db->trans_start();
$this->my_model->create($data);
$another_data = $this->second_model->read($second_data);
$this->another_model->create($another_data);
$this->db->trans_complete();

但是现在,我必须对总经理执行新规则。他有能力随时进行验证,而这种验证打破了验证链,因为它算作每个人都经过验证。

这种情况可能是一个例子:

User A asked for something
The manager validate
The general manager validate
The request is accepted

我不确定如何实现这一点,因为我意识到 2 个用户(例如总经理和副手)可以咨询同一个请求,一个拒绝,另一个验证,并且数据不再一致。

交易是否足够好?喜欢:

// User A asked for something
// The manager validate
// The deputy consult the request
// The manager consult the request
// The deputy validate:

    $this->db->trans_start();

    // check if already validated by the general manager
    if ($this->model->read($data)) {
        $this->db->trans_complete();
        // redirection to a warning page
    }
    else {
        $this->my_model->create($my_data);
    }
    $this->db->trans_complete();

    if ($this->db->trans_status() === FALSE)
        // redirection to another warning page

// The general manager wants to refuse at the same time but the deputy's transaction started first, so he's redirected to a warning page

    $this->db->trans_start();

    // check if already validated by anyone
    if ($this->model->read($data)) {
        $this->db->trans_complete();
        // redirection to a warning page
    }
    else {
        $this->my_model->create($my_data);
    }
    $this->db->trans_complete();

    if ($this->db->trans_status() === FALSE)
        // redirection to another warning page

// The validation chain continues after the deputy's validation

我想到了 LOCK TABLE 来禁止用户在其他人咨询相同请求时访问验证页面。但是TRANSACTION并且LOCK TABLE很难实现,因为它可以触发隐式提交,而且我没有足够的习惯来做到这一点。

我读到START TRANSACTION READ WRITE这可能是一个更好的解决方案,但我没有完全理解,我不确定如何正确实施。

任何人都可以帮助我实施好的策略,如果可能的话,如果需要的话使用这些 SQL 函数的方法?

标签: mysqlcodeignitertransactionslockingmariadb

解决方案


我找到了解决方案,我FOR UPDATE在查询之后使用了,这里是:

// the query for my results
private model_function_for_query() {
    $this->db->select('my_select');
    $this->db->from('my_table');
    $this->db->where('my_where_clause');

    return $this->db->get_compiled_select();
}

// the function to apply the FOR UPDATE on the query
public model_function() {
    $query = $this->model_function_for_query();
    $result = $this->db->query($query.' FOR UPDATE');

    return $result->row();
}

在我的控制器中:

// start the transaction
$this->db->trans_start();

// do the query, locking tables
$data = $this->my_model->model_function();

// check if the data has not changed
...

// if not, do the data treatment, else redirect to the warning page
...

// close the transaction
$this->db->trans_complete();

// check if the transaction failed, and do the stuff
if ($this->db->trans_status() === FALSE)
    ...
else
    ...

推荐阅读