Проблема:
Я написал функцию в моей модели для вставки заказа в мою базу данных.Я использую транзакции, чтобы убедиться, что все зафиксировано, иначе оно будет откатано.
Моя проблема заключается в том, что CodeIgniter не показывает ошибок базы данных, однако выполняет откат транзакции, а затем возвращает TRUE
для trans_status
.Однако это происходит только при наличии скидки на заказ.Если нет скидки на заказ, все фиксируется и работает правильно.
В настоящее время я использую CodeIgniter 3.19, PHP (7.2), mySQL (5.7) и Apache 2.4. (работает в Ubuntu 18.04)
Логика функции работает следующим образом:
- Вставляет массив заказов в
tbl_orders
- Сохраняет
order_id
, просматривает каждый из продуктов заказа (прикрепляет order_id
), вставляет продукт в tbl_order_products
, - Сохраняет
order_product_id
и присоединяет его к массиву параметров посещаемости пользователей и вставляет их вtbl_order_attendance
- Принимает массив платежных транзакций (присоединяет
order_id
) и вставляет его в tbl_transactions
- ЕСЛИ есть скидка на заказ , онуменьшает
discount_redeem_count
(количество подлежащих обмену кодов скидок) на 1.
Фактическая функция
[Функция]:
public function add_order(Order $order, array $order_products, Transaction $transaction = NULL){
$this->db->trans_start();
$order->create_order_code();
$order_array = $order->create_order_array();
$this->db->insert('tbl_orders', $order_array);
$order_id = $this->db->insert_id();
$new_order = new Order($order_id);
foreach($order_products as $key=>$value){
$order_products[$key]->set_order($new_order);
$order_product_array = $order_products[$key]->create_order_product_array();
$this->db->insert('tbl_order_products', $order_product_array);
$order_product_id = $this->db->insert_id();
$product = $order_products[$key]->get_product();
switch ($product->get_product_class()){
case 'Iteration':
$this->db->select('module_id, webcast_capacity, in_person_capacity');
$this->db->from('tbl_modules');
$this->db->where('iteration_id', $product->get_product_class_id());
$results = $this->db->get()->result_array();
break;
case 'Module':
$this->db->select('module_id, webcast_capacity, in_person_capacity');
$this->db->from('tbl_modules');
$this->db->where('module_id', $product->get_product_class_id());
$results = $this->db->get->result_array();
break;
}
if(!empty($results)){
foreach($results as $result){
$module_id = $result['module_id'];
if($result['webcast_capacity'] !== NULL && $result['in_person_capacity'] !== NULL){
$attendance_method = $order_products[$key]->get_attendance_method();
}elseif($result['webcast_capacity'] !== NULL && $result['in_person_capacity'] === NULL){
$attendance_method = 'webcast';
}elseif($result['webcast_capacity'] === NULL && $result['in_person_capacity'] !== NULL){
$attendance_method = 'in-person';
}
$order_product_attendance_array = array(
'order_product_id' => $order_product_id,
'user_id' => $order_products[$key]->get_customer(true),
'module_id' => $module_id,
'attendance_method' => $attendance_method,
);
$order_product_attendance[] = $order_product_attendance_array;
}
$this->db->insert_batch('tbl_order_product_attendance', $order_product_attendance);
}
if(!empty($order_products[$key]->get_discount())){
$discount = $order_products[$key]->get_discount();
}
}
if(!empty($transaction)){
$transaction->set_order($new_order);
$transaction_array = $transaction->create_transaction_array();
$this->db->insert('tbl_transactions', $transaction_array);
$transaction_id = $this->db->insert_id();
}
if(!empty($discount)){
$this->db->set('discount_redeem_count', 'discount_redeem_count-1', false);
$this->db->where('discount_id', $discount->get_discount_id());
$this->db->update('tbl_discounts');
}
if($this->db->trans_status() !== false){
$result['outcome'] = true;
$result['insert_id'] = $order_id;
return $result;
}else{
$result['outcome'] = false;
return $result;
}
}
Когда эта функция завершается со скидкой , оба trans_complete
и trans_status
возврат TRUE
.Однако транзакция никогда не совершается.
То, что я пробовал:
Я сбросил содержимое $this->db->error()
после каждого запроса, и нет ошибок в любом
Я использовал this->db->last_query()
, чтобы распечатать каждый запрос, а затем проверил синтаксис онлайн, чтобы увидеть, были ли какие-либо проблемы, не было ни одного.
Я также пытался перейти на использование ручных транзакций CodeIgniters, например:
[Пример]
$this->db->trans_begin();
// all the queries
if($this->db->trans_status() !== false){
$this->db->trans_commit();
$result['outcome'] = true;
$result['insert_id'] = $order_id;
return $result;
}else{
$this->db->trans_rollback();
$result['outcome'] = false;
return $result;
}
- Я пытался
echo
ing и var_dump
возвращая insert_ids
и все они работают, я также вывел affected_rows()
запроса UPDATE
, и он показывает, что 1 строка была обновлена.Тем не менее, ничего еще не было зафиксировано:
[Значения сброшены]
int(10) // order_id
int(10) // order_product_id
array(3) {
["module_id"]=> string(1) "1"
["webcast_capacity"]=> string(3) "250"
["in_person_capacity"]=> string(3) "250" } // $results array (modules)
array(1) {
[0]=> array(4) {
["order_product_id"]=> int(10
["user_id"]=> string(1) "5"
["module_id"]=> string(1) "1"
["attendance_method"]=> string(7) "webcast" } } // order_product_attendance array
int(9) // transaction_id
int(1) // affected rows
string(99) "UPDATE `tbl_discounts`
SET discount_redeem_count = discount_redeem_count- 1
WHERE `discount_id` = 1" // UPDATE query
- Я также пытался заменить последний запрос UPDATE
на совершенно другой, которыйпытается обновить другую таблицу с другими значениями.Этот запрос ТАКЖЕ не сработал, что заставляет меня думать, что я достиг своего рода ограничения памяти при транзакции.Однако при мониторинге mysqld
процессов ни у одного из них, похоже, нет резких скачков или трудностей.
- Я пытался отправить заказ без скидки, и весьпроцесс работает!Что приводит меня к мысли, что моя проблема связана с моим запросом ОБНОВЛЕНИЯ.[После обновления:] Но похоже, что запрос на обновление также работает.
Попытки предложений:
Мы попытались установить log_threshold
до 4, и просмотрел файлы журналов CodeIgniter, в которых нет истории отката.
Мы проверили журнал запросов MySQL:
[Журнал запросов]
2018-12-03T15:20:09.452725Z 3 Query UPDATE `tbl_discounts` SET discount_redeem_count = discount_redeem_count-1 WHERE `discount_id` = '1'
2018-12-03T15:20:09.453673Z 3 Quit
Это показывает, что *Команда 1113 * отправляется сразу после запроса UPDATE
.Это может инициировать откат, однако trans_status
возвращает TRUE
.
Я также изменил свой файл my.cnf
для mySQL, чтобы иметь innodb_buffer_pool_size=256M
и innodb_log_file_size=64M
.Там не было никаких изменений в результате.
- Как рекомендовано @ebcode, я изменил
UPDATE
запрос на использование simple_query()
вместо использования методов по умолчанию из класса построителя запросов CodeIgniter:
[Simple Query]
if(!empty($discount)){
$this->db->simple_query('UPDATE `tbl_discounts` SET '.
'discount_redeem_count = discount_redeem_count-1 WHERE '.
'`discount_id` = \''.$discount['discount_id'].'\'');
}
Однако это не повлияло на результат по-другому.
Если у вас есть идея, которую я еще не попробовал, или вам нужна дополнительная информация, пожалуйста, прокомментируйте, и я быстро отвечу.
Вопрос:
Почему trans_status
возвращает TRUE
, если ни одна из моих транзакций не фиксируется?
Чтобы попытаться прояснить ситуацию с пользователями, которые только что нашли этот вопрос, последние обновления к сообщению будут выделены курсивом *