【发布时间】:2019-05-03 00:58:07
【问题描述】:
问题:
我在我的模型中编写了一个函数来向我的数据库中插入一个订单。我正在使用事务来确保所有内容都提交,否则它将被回滚。
我的问题是 CodeIgniter 没有显示任何数据库错误,但是它正在回滚事务,但随后为 trans_status 返回 TRUE。但是,只有在订单有折扣时才会发生这种情况。如果订单没有折扣,则一切都会提交并正常工作。
我目前正在使用 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;
}
- 我已经尝试
echoing 和var_dumping 所有返回insert_ids并且它们都有效,我还输出了UPDATE查询的affected_rows(),它显示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 进程时,它们似乎都没有出现峰值或有困难。
- 我已尝试提交没有折扣的订单,整个过程正常!这让我相信我的问题出在我的 UPDATE 查询上。 [更新后:]但似乎更新查询也可以正常工作。
尝试过的建议:
我们尝试将
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
它表明在UPDATE 查询之后直接发送了一个QUIT 命令。这将启动回滚,但是 trans_status 正在返回 TRUE。
我还将 mySQL 的my.cnf 文件更改为具有innodb_buffer_pool_size=256M 和innodb_log_file_size=64M。结果没有任何变化。
- 按照@ebcode 的建议,我将
UPDATE查询更改为使用simple_query(),而不是使用CodeIgniter 查询生成器类中的默认方法:
[简单查询]
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?
为了让刚刚发现这个问题的用户更清楚,帖子的最新更新将以斜体显示 *
【问题讨论】:
-
您检查了 $discount['discount_id'] 值吗?
-
@Vickel 嘿,是的,我做到了。当我使用“$this->db->last_query()”时,它显示包含了“discount_id”值。 (在我的测试中,ID 值为 1)
-
您还没有在没有向我们展示的地方运行
$this->db->trans_strict(FALSE);吗? -
@DFriend 非常感谢您的评论!绝对不是,这是我检查的第一件事。
-
日志文件中也没有条目?
标签: php mysql codeigniter