我有一张包含多家公司发票的表格,每家公司都需要有自己的递增发票编号系统。
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值。
感谢您的任何建议
答案 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的工作方式可能有所不同,我还没有测试过。