0

已创建以下 Linq to SQL 事务以尝试创建无间隙的发票编号。假设有 2 个表:

表 1:发票编号。- 列 ID、序列号、增量 - 示例:1、10001、1

表 2:发票。- 列:ID、InvoiceNumber、名称 - 示例:1、10001、“Bob Smith”

        Dim db As New Invoices.InvoicesDataContext
        Dim lastInvoiceNumber = (From n In db.InvoiceNumbers Order By n.LastSerialNumber Descending
                          Select n.LastSerialNumber, n.Increment).First
        Dim nextInvoiceNumber As Integer = lastInvoiceNumber.LastSerialNumber + lastInvoiceNumber.Increment
        Dim newInvoiceNumber = New Invoices.InvoiceNumber With {.LastSerialNumber = nextInvoiceNumber, .Increment = lastInvoiceNumber.Increment}
        Dim newInvoice = New Invoices.Invoice With {.InvoiceNumber = nextInvoiceNumber, .Name = "Test" + nextInvoiceNumber.ToString}
        db.InvoiceNumbers.InsertOnSubmit(newInvoiceNumber)
        db.Invoices.InsertOnSubmit(newInvoice)
    db.SubmitChanges()

一切正常,但是否有可能使用这种方法,如果两个用户同时进行交易,他们可能会拿起相同的发票号码?如果是这样,是否有更好的方法使用 Linq to Sql?

4

2 回答 2

0

您始终可以使用 lock() 确保事务不会同时在多个线程中运行:

private static object myLockObject = new object();
....
....
public class MyClass
{
...
public void TransactionAndStuff()
{
    lock(myLockObject) 
    {
        // your linq query
    }
}
于 2013-04-19T07:54:52.677 回答
0

在处理事务数据库时,序列中的间隙是不可避免的。

首先,您不能使用SELECT max(id)+1,因为它可能会同时id执行 2 个事务。这意味着您必须使用数据库本机自动增量列(MySQL、SQLite)或数据库序列(PostgreSQL、MSSQL、Oracle)来获取下一个可用id的 .

但即使使用自增序列也不能解决这个问题。想象一下,您有 2 个数据库连接,几乎同时启动了 2 个并行事务。第一个id从自动增量序列中获得了一些,它变成了以前使用的值 +1。一纳秒后,第二笔交易获得 next id,现在是 +2。现在想象第一个事务由于某种原因回滚(遇到错误,您的代码决定中止它,程序崩溃 - 您命名它)。之后,第二个事务以id+2 提交,在id编号上造成了差距。

但是如果这样的并行事务的数量超过 2 个呢?您无法预测,也无法告诉当前正在运行的事务重用id被放弃的 s。

理论上可以重复使用废弃的 id。然而,在实践中,它在数据库上的成本非常高,并且当多个会话尝试做同样的事情时会产生更多的问题。

TDLR:别再打了,用过的 id 之间的差距是完全正常的。

于 2013-04-18T03:36:07.420 回答