Транзакции Codeigniter

Я использую транзакции Codeigniter

$this->db->trans_start();
$this->db->query('AN SQL QUERY...');
$this->db->trans_complete();

Это отлично работает, проблема в том, что внутри trans_start и trans_complete я вызываю другие функции, и эти функции имеют дело с базой данных, поэтому они содержат вставки и обновления, а также некоторые удаления... например:

$this->db->trans_start();
 $this->utils->insert_function($data);
 $this->utils->update_function2($test);
$this->db->trans_complete();

Теперь, если эти функции выполняются и возникают какие-либо ошибки, CodeIgniter не будет выполнять откат.

Каков наилучший способ справиться с такой проблемой?

Единственное решение, которое я имею в виду, - это вернуть ошибку из этих функций, а внутри этих функций добавить (trans_stat и trans_complete). И если он возвращает ошибку, проверьте и сделайте $this->db->trans_rollback

ex:

    $this->db->trans_start();
     $result = $this->utils->insert_function($data);
     if($result === false){
       $this->db->trans_rollback();
     }
    $this->db->trans_complete();

Есть ли лучший способ сделать это?

Обновление 1:

По запросу образец внешней функции, которую я вызываю:

   // insert_function contains

    $rec = array(
        'numero' => $numero,
        'transaction_id' => $id,
        'debit' => $product_taxes['amount_without_taxes'],
        'date' => $data['date_transaction'],
    );
    $this->addExerciceAccountingRecords($rec);

  and addExerciceAccountingRecords contains

   function addExerciceAccountingRecords($records) {
    $this->db->insert('transactions_exercices', $records);
    }

person Tarek    schedule 05.03.2013    source источник
comment
Какой механизм хранения вы используете для своих таблиц MySQL? Кроме того, как узнать, что откат не удался?   -  person Marc Audet    schedule 05.03.2013
comment
@MarcAudet INNODB, я знаю, потому что когда есть откат, он не применяется к таблицам, измененным во время вызова функции внутри trans_start   -  person Tarek    schedule 05.03.2013
comment
Можете ли вы опубликовать код в utils-›insert_function и utils-›insert_function2? Я имею представление о том, в чем может быть дело...   -  person Marc Audet    schedule 05.03.2013
comment
@MarcAudet Я обновил свой вопрос.   -  person Tarek    schedule 05.03.2013
comment
Еще один вопрос: утилиты есть в папке с библиотеками?   -  person Marc Audet    schedule 05.03.2013
comment
да, он содержит вспомогательные функции   -  person Tarek    schedule 05.03.2013
comment
Дайте мне несколько минут, чтобы напечатать ответ для вас...   -  person Marc Audet    schedule 05.03.2013
comment
Я предлагаю проголосовать за любые ответы, которые вы считаете полезными   -  person Madbreaks    schedule 15.05.2013
comment
Пример roytuts.com/codeigniter-transaction-example/   -  person user3470953    schedule 03.07.2015


Ответы (6)


Использование transactions означает поддержку баз данных для безопасной вставки данных. Таким образом, в Codeigniter мы пишем все функции, связанные с базой данных, в Модели, а не в Контроллере. И во втором коде (который не работает) вы указали там модель (utils). Так просто, я уверен, что это не сработает. Потому что это не вставка данных с параллельной моделью и контроллером. Транзакция должна быть закодирована в модели (в своем ответе я напишу в модели).


Загрузить и это содержимое

  1. Библиотека базы данных
  2. Класс модели
  3. помощник URL
  4. Сессия

Предположения

В вашем коде вы использовали $data и $test в качестве массива. Итак, я предполагаю, что есть два массива для вставки и обновления данных.


Ваши наборы данных

$data = array(
   'title' => 'My title' ,
   'name' => 'My Name' ,
   'date' => 'My date'
);

$id = 007;
$test = array(
   'title' => $title,
   'name' => $name,
   'date' => $date
);

Ваш код

$this->db->trans_start(); # Starting Transaction
$this->db->trans_strict(FALSE); # See Note 01. If you wish can remove as well 

$this->db->insert('table_name', $data); # Inserting data

# Updating data
$this->db->where('id', $id);
$this->db->update('table_name', $test); 

$this->db->trans_complete(); # Completing transaction

/*Optional*/

if ($this->db->trans_status() === FALSE) {
    # Something went wrong.
    $this->db->trans_rollback();
    return FALSE;
} 
else {
    # Everything is Perfect. 
    # Committing data to the database.
    $this->db->trans_commit();
    return TRUE;
}

Примечания

  1. По умолчанию Codeigniter выполняет все транзакции в строгом режиме. Когда строгий режим включен, если вы выполняете несколько групп транзакций, в случае сбоя одной группы будет выполнен откат всех групп. Если строгий режим отключен, каждая группа обрабатывается независимо, это означает, что сбой одной группы не повлияет на другие.
person Abdulla Nilam    schedule 09.01.2016
comment
trans_complete() уже выполняет проверку состояния и откат/фиксацию - person Alex; 01.08.2016
comment
@AL-zami Почему ты их удаляешь ?? Не конфликтовать с контентом - person Abdulla Nilam; 25.08.2016
comment
@spartan те несколько строк, которые я отредактировал, были для ручных транзакций. См. документацию для вашего собственного codeigniter. com/user_guide/database/transactions.html - person AL-zami; 25.08.2016
comment
@AL-zami, братан, чтобы справляться с ошибками. Проверьте этот codeigniter.com/user_guide/database/. - person Abdulla Nilam; 25.08.2016
comment
если trans_complete() зафиксируется автоматически, в ELSE случае она зафиксируется снова... вам не кажется, что это проблема! - person AL-zami; 25.08.2016
comment
есть два варианта: 1) удалить условие else или 2) удалить $this-›db-›trans_complete(), пожалуйста, проверьте руководство и обновите свой ответ. @Spartan - person Jobayer; 19.09.2016
comment
Обязательно используйте $this-›db-›trans_begin() при выполнении ручных транзакций, а НЕ $this-›db-›trans_start(). - person Shihas; 13.10.2016
comment
@Шихас Почему? При проверке кода trans_start() на самом деле вызывает trans_begin() с теми же параметрами, и дополнительная проверка также не выполняется. Возможно читабельность. - person Muhammad Ali; 26.03.2017
comment
в моем случае я хочу сделать заказ в то время, когда один заказ имеет несколько элементов заказа в отдельной таблице, поэтому, когда я делаю заказ, я хочу совершить транзакцию. шаг-1: я вставляю заказ в таблицу заказов. шаг 2: на основе вставленного идентификатора заказа используйте его в таблице элементов заказа, он кратен в одном заказе. когда элемент заказа вставлен в это время, я проверяю доступность времени заказа, если количество элемента заказа недоступно, я хочу отменить всю транзакцию, но $this->db->trans_status() становится правдой, как это сделать. Я пробую много, но не работает, когда доступность не работает. Я просто $this->db->trans_rollback();, но откат невозможен - person Pradip Talaviya; 24.02.2018
comment
Привет @AbdullaNilam, действительно ли возможно запустить $this-›db-›trans_complete(); а затем запустите $this-›db-›trans_rollback(); ? - person Valter Ekholm; 23.09.2020
comment
@ВальтерЭкхольм, да. trans_complete записывайте свои данные только в БД. в случае неудачи откат удалит частичное сохранение в БД - person Abdulla Nilam; 24.09.2020

То, что я пробовал, было скорее уловкой, но это сработало для меня.

$this->db->trans_begin();
  $rst1=  $this->utils->insert_function($data);
  $rst2 =  $this->utils->update_function2($test);
if($this->db->trans_status() === FALSE || !isset($rst1) || !isset($rst2)){
   $this->db->trans_rollback();
}else{
   $this->db->trans_commit();
}
person Heshan Rajapaksha    schedule 08.08.2016

Я подозреваю, что проблема связана с тем, как CodeIgniter обрабатывает объекты.

Если вы перейдете к документации CI в разделе «Создание библиотек» по адресу:
http://ellislab.com/codeigniter/user-guide/general/creating_libraries.html
и просмотрите раздел, посвященный:

$CI =& get_instance();
$CI->load->helper('url');
$CI->load->library('session');
$CI->config->item('base_url');

В вашем основном контроллере вы загрузили/создали экземпляр класса базы данных либо с помощью автоматической загрузки, либо явно загрузив класс.

Затем вы открываете транзакцию, а затем получаете доступ к функциям базы данных через библиотеку utils.

Однако, как только вы используете $this-db в своей библиотеке, вы фактически получаете доступ к другой копии экземпляра базы данных, а НЕ к той, которая связана с вашей транзакцией.

Чтобы получить доступ к тому же экземпляру, вам нужно использовать функцию get_instance().

Думаю, это должно решить вашу проблему. Ваш оригинальный стиль кодирования для разделения функций на различные модули превосходен. Вам просто нужно понять эту дополнительную деталь.

Пожалуйста, попробуйте и убедитесь, что откат работает так, как вы ожидаете.

Нутро кода состоит из следующего контроллера:

$this->db->trans_start();
$this->User_profile_m->create_new_user_profile();
$this->User_profile_m->create_new_user();
$this->db->trans_complete(); 

и простая модель user_profile_m для сохранения данных:

function create_new_user()
{
    $data['user_name_usr'] = $this->input->post('user_name');
    $data['create_date_usr'] = NULL;

    $this->db->insert('user_usr', $data);  
}

function create_new_user_profile()
{
    $data['user_name_pro'] = $this->input->post('user_name');
    $data['user_description_pro'] = $this->input->post('user_description');
    $data['create_date_pro'] = NULL;

    $this->db->insert('user_profile_pro', $data);  
}

По сути, демонстрация пытается сделать две вставки (по одной в каждую из двух таблиц). Если одна вставка терпит неудачу, другая откатывается.

Я создал это в CodeIgniter 2.1.3, и я могу сделать файлы приложения доступными через GitHub или заархивировать их и отправить вам.

person Marc Audet    schedule 05.03.2013
comment
Извините, возможно, я привел плохой пример, проблема возникает, даже если функция вставки находится в той же модели, и я вызываю ее с помощью ($this-›insertFunction...) - person Tarek; 06.03.2013
comment
Привет, Тарек, ты пробовал get_instance()? Мне немного любопытно об этом; вы не делаете ничего необычного. Позвольте мне подумать об этом за чашкой кофе, пожалуйста, зайдите позже сегодня. - person Marc Audet; 06.03.2013
comment
@Marc Audet: когда операция обновления возвращает 0 (затронутая строка), тогда транзакция откатывается или нет? Спасибо. - person secretlm; 05.05.2013
comment
@secretim Хороший вопрос. Вы действительно должны проверять $this->db->trans_status() вместо $this->db->affected_rows(), поскольку результат затронутой строки может варьироваться в зависимости от того, где именно вы помещаете оператор (внутри или снаружи блока транзакции). - person Marc Audet; 06.05.2013


Примечание. Обязательно используйте $this->db->trans_begin() при выполнении ручных транзакций, а НЕ $this->db->trans_start().

$this -> db -> trans_begin(); 
$this -> utils -> insert_function ( $data );
$this -> utils -> update_function2 ( $test ); 
$this -> db -> trans_complete ();

Сертифицировать в случае использования MySql, использовать в формате InnoDb

person Diego    schedule 30.01.2014
comment
Почему за это проголосовали? В обеих версиях (2 и 3) это start/complete и begin/rollback/commit. - person akinuri; 14.05.2021

Попробуйте эту процедуру. Это действительно работает для меня :)

$this->db->trans_start();
   $this->utils->insert_function($data);
   $this->utils->update_function2($test);
if($this->db->trans_status() === FALSE){
   $this->db->trans_rollback();
}else{
   $this->db->trans_complete();
}
person Kahlil Vanz    schedule 21.07.2014
comment
trans_complete() уже выполняет проверку состояния и откат/фиксацию - person Alex; 01.08.2016

Для одной записи вставки или обновления вы можете использовать функцию Effective_rows.

$this->db->insert('table_name', xss_clean($data));


//Check if there is a record affected
if($this->db->affected_rows() > 0)
              {
                  return true;
              }
              else
              { 
                  // if not succeeded
                  // check your last query 
                  die($this->db->last_query());
              }
person bdalina    schedule 01.03.2019