【问题标题】:Two incrementing columns in the same table同一个表中的两个递增列
【发布时间】:2015-04-16 20:31:51
【问题描述】:

我有一个包含几家公司发票的表格,每个公司都需要有自己的递增发票编号系统。

id | invoiceId | companyId
--------------------------
1  | 1         | 1
2  | 2         | 1
3  | 1         | 2
4  | 1         | 3

我希望使用类似于 approach for MyISAM outlined here 的唯一复合键来实现这一点,但似乎使用 InnoDB 是不可能的。

我需要在插入后立即返回新 ID,如果我尝试使用 PHP 实现这一点,我担心会产生竞争条件。

创建触发器是我的最佳选择吗?如果是,那会是什么样子?我没有使用触发器的经验,我对使用after insert 触发器的研究让我对this quote from the MariaDB documentation 感到担心:

限制

您不能在视图上创建 AFTER 触发器。你不能更新 新的价值观。您不能更新旧值。

感谢您的建议

【问题讨论】:

  • 你可以创建一个增量表,例如userid int, increment int,但是使用 myisam,您必须执行全表锁定才能安全地更新值。至少使用 innodb 你有行级锁。
  • 您实际上想要在 table 上使用“插入前”触发器,这样警告似乎就无关紧要了。
  • @GordonLinoff 谢谢,这给了我一个新的视角。我会调查的

标签: php mysql mariadb


【解决方案1】:

除了获取下一个值之外,您还需要添加唯一索引。下一个值最好通过使用触发器或事务中的某个过程查询表来获得。在这种情况下,视图上的触发器注释无关紧要。

唯一索引在 companyId 上,需要invoiceId 以防止在同一公司上运行的两个插入进程添加发票,然后这两个插入进程可能最终都具有相同的 invoiceId。更好的是当您切换到 InnoDB 以便您可以使用事务时:然后几乎同时启动的 2 个进程可以从事务隔离中受益,因此它们将被序列化,并且您将获得 2 个唯一递增的发票 ID,而无需处理代码中的唯一索引异常。

【讨论】:

    【解决方案2】:

    据我所知,mysql的last_id是基于连接的,不是全局的,进程间共享的。

    使用这个简单的脚本我已经验证了我的担忧

    (注意这是codeigniter语法,但比较容易理解)

    我在 10 秒内访问了以下函数两次(在不同的浏览器窗口中)

    function test(){
        $arr['var'] = rand(0,100000000);
        $this->db->insert('test_table',$arr);
        sleep(30);
        $id = $this->db->insert_id();
        var_dump($id);
    }
    

    有趣的是,我没有得到“2”作为回应,而是恭敬地得到了 1 和 2。当您查看底层函数时,这会更有意义

    function insert_id()
    {
        return @mysqli_insert_id($this->conn_id);
    }
    

    这解决了返回的 ID,您的竞争条件是基础查询的产物,基本上是“选择 MAX(invoiceId) WHERE companyID = X”并在其中添加 +1,然后插入它。

    这应该可以在插入之前使用表锁定,但这取决于您希望该表每秒更新多少次。

    注意,在持久连接上,last_insert_id 的工作方式可能不同,我还没有测试过。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-24
      • 2022-01-19
      • 1970-01-01
      • 2023-01-21
      • 1970-01-01
      • 2012-05-29
      • 2019-05-29
      • 2022-01-18
      相关资源
      最近更新 更多