使用锁定表时的事务+回滚

时间:2014-08-14 17:28:55

标签: php mysql codeigniter

这是一个跟进: php/mysql transaction not rolling back on failure (Codeigniter framework)

我在上面的链接中实现了建议的模式。我的问题是:

  1. 每次查询失败时是否需要回滚?看来我必须检查每个查询的结果,如果失败则进行回滚。这似乎有点重复。

    $this->db->query("SET autocommit=0");
    
    //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');
    
        if (!$this->db->insert('sales',$sales_data))
        {
            $this->db->query("ROLLBACK");
            $this->db->query('UNLOCK TABLES');
            return -1;
        }
    
  2. ... ...

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

2 个答案:

答案 0 :(得分:1)

您应该放弃使用LOCK TABLESUNLOCK TABLES;,因为它可以触发隐式提交。相反,您应该考虑使用SELECT ... FOR UPDATESELECT ... LOCK IN SHARED MODE

如果您使用的是MySQL 5.6,请尝试使用

启动事务
  • START TRANSACTION READ WRITE;
  • START TRANSACTION READ ONLY;

我在DBA StackExchange中写过这篇文章(参见row locking within ACID transaction innodb

如果您仍希望使用LOCK TABLES;UNLOCK TABLES,请注意LOCK TABLES开始新的交易,ROLLBACKCOMMIT仍然是强制性的,因为UNLOCK TABLES;触发隐式提交。 ROLLBACK让您有机会丢弃交易所持有的更改。 UNLOCK TABLES;将提交您可能想要撤消的更改。

唯一的隐式回滚是终止数据库连接。

答案 1 :(得分:0)

Codeigniter具有内置交易支持,您不需要手动执行这些操作。

我相信它在CodeIgniter v3中得到了改进(仍在开发中)。

基本上,你所要做的就是这样:

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

当查询失败时,调用trans_complete()会自动回滚。

如果你想自己处理错误,你可以这样做:

$this->db->trans_begin();

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

if ($this->db->trans_status() === FALSE)
{
        $this->db->trans_rollback();
}
else
{
        $this->db->trans_commit();
}

请记住,我指的是CodeIgniter v3,你可以把它从github上取下来,因为我在一年前抛弃了CodeIgniter v2。