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