【问题标题】:php/mysql transaction not rolling back on failure (Codeigniter framework)php/mysql 事务在失败时不回滚(Codeigniter 框架)
【发布时间】:2014-06-06 23:10:58
【问题描述】:

下面我有以下代码。如果事务失败,则不会回滚。如果我删除锁定表语句,它会回滚。为了使用锁和事务,我需要做什么特别的事情吗?

function save ($items,$customer_id,$employee_id,$comment,$show_comment_on_receipt,$payments,$sale_id=false, $suspended = 0, $cc_ref_no = '', $auth_code = '', $change_sale_date=false,$balance=0, $store_account_payment = 0)
{
    if(count($items)==0)
        return -1;

    $sales_data = array(
        'customer_id'=> $this->Customer->exists($customer_id) ? $customer_id : null,
        'employee_id'=>$employee_id,
        'payment_type'=>$payment_types,
        'comment'=>$comment,
        'show_comment_on_receipt'=> $show_comment_on_receipt ?  $show_comment_on_receipt : 0,
        'suspended'=>$suspended,
        'deleted' => 0,
        'deleted_by' => NULL,
        'cc_ref_no' => $cc_ref_no,
        'auth_code' => $auth_code,
        'location_id' => $this->Employee->get_logged_in_employee_current_location_id(),
        'store_account_payment' => $store_account_payment,
    );

    $this->db->trans_start();

    //Lock tables invovled in sale transaction so we don't have deadlock
    $this->db->query('LOCK TABLES '.$this->db->dbprefix('customers').' WRITE, '.$this->db->dbprefix('sales').' WRITE, 
    '.$this->db->dbprefix('store_accounts').' WRITE, '.$this->db->dbprefix('sales_payments').' WRITE, '.$this->db->dbprefix('sales_items').' WRITE, 
    '.$this->db->dbprefix('giftcards').' WRITE, '.$this->db->dbprefix('location_items').' WRITE, 
    '.$this->db->dbprefix('inventory').' WRITE, '.$this->db->dbprefix('sales_items_taxes').' WRITE,
    '.$this->db->dbprefix('sales_item_kits').' WRITE, '.$this->db->dbprefix('sales_item_kits_taxes').' WRITE,'.$this->db->dbprefix('people').' READ,'.$this->db->dbprefix('items').' READ
    ,'.$this->db->dbprefix('employees_locations').' READ,'.$this->db->dbprefix('locations').' READ, '.$this->db->dbprefix('items_tier_prices').' READ
    , '.$this->db->dbprefix('location_items_tier_prices').' READ, '.$this->db->dbprefix('items_taxes').' READ, '.$this->db->dbprefix('item_kits').' READ
    , '.$this->db->dbprefix('location_item_kits').' READ, '.$this->db->dbprefix('item_kit_items').' READ, '.$this->db->dbprefix('employees').' READ , '.$this->db->dbprefix('item_kits_tier_prices').' READ
    , '.$this->db->dbprefix('location_item_kits_tier_prices').' READ, '.$this->db->dbprefix('location_items_taxes').' READ
    , '.$this->db->dbprefix('location_item_kits_taxes'). ' READ, '.$this->db->dbprefix('item_kits_taxes'). ' READ');


    $this->db->insert('sales',$sales_data);
    $sale_id = $this->db->insert_id();

    //A bunch of mysql other queries to save a sale


    $this->db->query('UNLOCK TABLES');

    $this->db->trans_complete();

    if ($this->db->trans_status() === FALSE)
    {
        return -1;
    }

    return $sale_id;

}

【问题讨论】:

    标签: php mysql codeigniter transactions


    【解决方案1】:

    我认为这主要是因为 MySQL“LOCK TABLES”在尝试锁定表之前会提交任何活动事务

    实际上,这两个动作(LOCKING 和 TRANSACTIONS)之间的交互在 MySQL 中看起来相当棘手,因为它在 the MySQL manual page.

    中非常清晰完整地概述了

    建议的解决方案是通过发出SET autocommit = 0 命令关闭autocommit 标志(默认为开启,因此通常每个发出的查询都会在执行后自动提交):

    使用 LOCK TABLES 和 UNLOCK TABLES 的正确方法 事务表 [..] 是用 SET 开始事务 autocommit = 0(不是 START TRANSACTION),后跟 LOCK TABLES,然后 在明确提交事务之前不要调用 UNLOCK TABLES。 例如,如果您需要写入表 t1 并从表 t2 中读取, 你可以这样做:

    您的代码可能如下所示:

    $this->db->query("SET autocommit=0");
    $this->db->query("LOCK TABLES...."); // your query here
    $this->db->query("COMMIT");
    $this->db->query("UNLOCK TABLES');
    

    【讨论】:

    • 只是一个后续问题。似乎即使我这样做并且出现错误,事务也已部分提交。如果出现错误,有没有办法在不提交事务的情况下做到这一点?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多