同一个表中的两个递增列

时间:2015-04-16 20:31:51

标签: php mysql mariadb

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

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触发器。你无法更新   新的价值观。您无法更新OLD值。

感谢您的任何建议

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

据我所知,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的工作方式可能有所不同,我还没有测试过。