关于symfony:Symfony2、Doctrine和MySQL:如何生成发票号

Symfony2, Doctrine and MySQL: how to generate invoice number

使用Symfony2.0、Doctrine和MySQL,我需要按照下一个格式自动生成相关发票号:

年/自增

例如,2012 年的发票:

1
2
3
2012/00000001
2012/00000002
2012/00000003

等...

该发票编号将使用我的 MySQL 数据库的采购表中的 invoice_number 字段进行存储。

问题是,我如何查询数据库以返回特定年份的最后一个自增数?

换句话说(伪代码):

1
2
3
4
5
6
function new_invoice(){
    $year = today.year;
    select last invoice_number where year = $year;
    $new_invoice_number = increment invoice_number;
    store $year ."/" . $new_invoice_number;
}

我该怎么做呢?


首先,symfony2 和 dictionary2 都不是您的问题和解决方案的一部分。其次,您可能要考虑在您的 invoice_number 中存储一个 /,主要是因为您需要为此字段设置一个 varchar,它在索引和查询项目等方面的性能比整数差。

也就是说,您想要的可以通过多种方式实现,具体取决于您的需求:

选择最后一个条目,加一,保存

此解决方案仅在您没有太多写入购买表或这些写入由一个进程(例如一批)完成时才有效,您可以在其中等待一个项目被写入并且如果成功写下一个。

只需从数据库中选择最后一个条目,获取invoice_number,加一,保存。如果年份不同,请从一个开始。

当然,如果你每秒有很多写入,你会遇到麻烦,因为在你写一行的那一刻,另外两个可能已经读取了旧的最后一个 invoice_number,将它加一并尝试存储它(导致错误因为它们必须是唯一的)。

读取时动态计算

如果您不需要经常使用 invoice_number,此解决方案效果很好。你可以对一个想法有一个正常的 auto_increment 。对于每一年,您将去年的最后一个 id 存储在一些帮助表中。当您读取一行时,您可以通过获取年份、上一年的最后一个 id 并从 auto_increment 中减去它来计算 id。

开销当然是您每次都需要计算发票。根据您实际实现它的方式以及数据库负载是什么,这可能是从不明显到非常慢的任何地方。

让 invoice_number 为空,而不是计算它

这可以通过多种不同的方式完成,如果您不想摆弄事务等,捕获失败的写入等,这是一个非常简洁的解决方案。这个想法是首先使用空的 invoice_number 存储数据,然后在保存数据时计算 invoice_number 并更新数据集。

您可以将它与之前的想法结合起来,像上面描述的那样计算 invoice_number,然后用这个数字更新数据集,而不是每次都重新计算。您还可以有一个 cronjob 或寻找具有空 invoice_number 的行的东西,以及仅由该 cronjob 使用的助手表中的计数器之类的东西。他拿起计数器,将其递增,使用这是数据集的新发票并保存计数器和数据集。

尝试,出错时重复

这是一个丑陋的解决方案,但它可以工作并且在某些情况下可能没问题。您选择最后一个 invoice_number,将其加一,保存当前数据集。如果失败,则重复该过程。你这样做直到你成功储蓄。您需要确保在实际数据库上进行选择(doctrine2 可能会缓存结果,这意味着您始终获取旧数据集,增加相同的数字并因此一遍又一遍地遇到相同的错误)并且如果您有一些 master/从站设置不适用于从站,因为它可能不是最新的。

我不喜欢这个解决方案,但正如我所说,这是值得考虑的。

每年一张桌子

每年可以将数据保存在一个表中。这样你就可以使用 auto_increment。当然,外键会变得混乱,并且在许多表上进行选择并不比只有一张表那么容易。您当然可以引入一个组合所有这些表的视图。

使用存储过程

我从来都不是存储过程的粉丝,主要是因为它将逻辑从应用程序带到数据库,因此更难掌握发生了什么("这个值是从哪里来的?")。但是您可以有一些存储过程来计算 invoice_number 并将其与 INSERT INTO

上的其他值一起存储

只需使用 auto_increment

如果你只使用 auto_increment,你会为自己省去很多麻烦。您始终可以将年份保存在另一列中并将两者一起显示。当然,如果您的要求来自产品所有者,这可能是不可能的。但是,如果您有任何方法,请尝试一下!

...

可能还有更多。这些只是我的想法。