我们已经为Billing系统实施了一个web应用程序。我有一个字符串列来存储发票号。这一栏必须禁止数字之间的差距。
Id InvoiceNumber(Desired) InvoiceNumber(Actual)
1 001 001
2 002 002
3 003 005
在伪代码中
using (TransactionScope _ts = new TransactionScope())
{
var _lastGeneratedRecDetails = _db.StudentReceipts
.Where(r => r.Status == true
&& r.StudentRegistration.StudentWalkInn.CenterCode.Id == _centreCodeId
&& EntityFunctions.TruncateTime(r.DueDate.Value) >= _startDate.Date
&& EntityFunctions.TruncateTime(r.DueDate.Value) <= _endDate.Date)
.AsEnumerable()
.OrderByDescending(x => x.ReceiptNo != null ? Int32.Parse(x.ReceiptNo) : 0)
.FirstOrDefault();
var _newReceiptNo=Convert.ToInt32(_lastGeneratedRecDetails.ReceiptNo) + 1
....
....
_ts.complete();
}
问题一切都运行正常,直到50thinvoice,之后系统突然跳过2张发票并生成Invoice 52.我们调查了系统状态,发现系统没有被外部篡改,我们也推断出没有人从工作台访问数据库。这是一个重大问题,因为它也有法律后果。
我已经完成了几项研究,并指出了以下解决方案
1.在事务期间锁定整个表并在完成后将其释放。我担心的是如果在发布锁之前服务器崩溃/互联网连接断开连接会发生什么
using (Entities entities = new Entities())
using (TransactionScope scope = new TransactionScope())
{
//Lock the table during this transaction
entities.Database.ExecuteSqlCommand("SELECT TOP 1 KeyColumn FROM MyTable WITH (TABLOCKX, HOLDLOCK)");
//Do your work with the locked table here...
//Complete the scope here to commit, otherwise it will rollback
//The table lock will be released after we exit the TransactionScope block
scope.Complete();
}
2.使用storedprocedure生成invoicenumber,程序将是这样的事情
START TRANSACTION;
SELECT number FROM invoice_numbers WHERE name='main' FOR UPDATE;
assign the number to the invoice and set its status to finalized;
UPDATE invoice_numbers SET number = number + 1 WHERE name='main';
COMMIT;
如果有人能帮助我选择哪一个可能是正确的解决方案,那将是非常有帮助的