Как запретить 2 пользователям редактировать одни и те же данные в веб-приложении с использованием MySQL (если возможно, с CodeIgniter) - PullRequest
1 голос
/ 21 марта 2019

Я использую CodeIgniter 3 и MariaDB 5.0 в моей среде разработки (но MySQL 5.6 в среде prod).

Я создал веб-приложение и внедрил цепочку проверки для приема пользовательских запросов.

Например:

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 при необходимости?

1 Ответ

0 голосов
/ 29 марта 2019

Я нашел решение, я использовал 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
    ...
...