Linq to sql 如何使用LINQtoSQL作为序列号生成器以避免出现漏洞?

Linq to sql 如何使用LINQtoSQL作为序列号生成器以避免出现漏洞?,linq-to-sql,Linq To Sql,已创建以下Linq to SQL事务,以尝试创建无间隙的发票编号。 假设有两个表: 表1:发票编号- 列ID、序列号、增量- 示例:11001,1 表2:发票- 列:ID、发票编号、名称- 示例:11001,“鲍勃·史密斯” 所有这些都可以正常工作,但是使用这种方法,如果两个用户同时进行交易,那么他们可能会选择相同的发票号吗? 如果是这样,是否有更好的方法使用Linq to Sql?在处理事务性数据库时,序列中的差异是不可避免的 首先,您不能使用SELECT max(id)+1,因为它可能为同时

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

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

表2:发票- 列:ID、发票编号、名称- 示例:11001,“鲍勃·史密斯”

所有这些都可以正常工作,但是使用这种方法,如果两个用户同时进行交易,那么他们可能会选择相同的发票号吗?
如果是这样,是否有更好的方法使用Linq to Sql?

在处理事务性数据库时,序列中的差异是不可避免的

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

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

但若此类并行事务的数量超过2,该怎么办?您无法预测,也无法告诉当前正在运行的事务重用已放弃的
id
s

从理论上讲,重用废弃的ID是可能的。然而,在实践中,它对数据库的开销非常高,并且当多个会话尝试执行相同的操作时,会产生更多的问题


TDLR:停止对抗,已用ID中的漏洞是完全正常的。

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

        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()
private static object myLockObject = new object();
....
....
public class MyClass
{
...
public void TransactionAndStuff()
{
    lock(myLockObject) 
    {
        // your linq query
    }
}