我在我的项目中使用事务范围。隔离级别为IsolationLevel.ReadCommitted
我也尝试了IsolationLevel.RepeatableRead
using (DBOperations dboperation = new DBOperations())
{
GetAccountVoucherNuber();
}
我从交易范围调用此方法。
private void GetAccountVoucherNuber() {
var _dB0010013 = _dB0010013Repository.GetAll().Where(e = > e.Category == "D" && e.CategoryType == "TSNO" && e.Branch == Branch && EntityFunctions.TruncateTime(e.OnDate) == EntityFunctions.TruncateTime(TranInit.EntryDate) && e.CodeOne == BatchCode).FirstOrDefault();
if (_dB0010013 == null) {
_dB0010013 = new DB0010013();
_dB0010013.Branch = Branch;
_dB0010013.Category = "D";
_dB0010013.CategoryType = "TSNO";
_dB0010013.CodeOne = BatchCode;
_dB0010013.CodeTwo = "";
_dB0010013.CodeThree = "";
_dB0010013.OnDate = TranInit.EntryDate;
_dB0010013.Note = "";
_dB0010013.LastNo = 1;
var _operationStatus = _dB0010013Repository.AddAndSave(_dB0010013, false);
} else {
_dB0010013.LastNo += 1;
var _operationStatus = _dB0010013Repository.UpdateAndSave(_dB0010013, false);
}
}
当两个或多个用户同时提交页面时。
对于两次交易,我得到相同的号码。
例如。假设user1得到lastNo = 85 + = 1 = 86
同时user2也得到lastNo = 85 + = 1 = 86
因此两个不同的交易同样不适用。
获取值后如何锁定Select语句。或者是什么方法来处理它。
我搜索了很多,但没有找到任何解决方案。
我的DbOperataion课程已添加以供参考。
public class DBOperations:IDisposable
{
private TransactionScope transactionscope;
public void Dispose()
{
if (this.transactionscope != null)
this.transactionscope.Dispose();
}
public DBOperations()
{
this.Initialize();
}
public void Initialize()
{
try
{
this.Dispose();
TransactionOptions transactionoption = new TransactionOptions();
transactionoption.Timeout = new TimeSpan(1, 0, 0);
transactionoption.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
this.transactionscope = new TransactionScope(TransactionScopeOption.Required, transactionoption);
}
catch (Exception ex)
{
throw new Exception("Data Error " + ex.Message);
}
}
}
答案 0 :(得分:0)
在这种情况下,我通常会制作一个额外的表AccountVoucherNumberGenerator
来保存最后一个数字。您可以执行插入并使用Identity Insert(最简单的方法),也可以选择仅使用1行并使用上次使用的数字更新该行。
答案 1 :(得分:0)
我更喜欢按Transaction
和TransactionOptions
类设置TransactionScope
。从Isolation Level on Wiki开始,RepeatableRead
级别就足够了。
using System.Transactions;
....
TransactionOptions options = new TransactionOptions();
options.IsolationLevel = IsolationLevel.RepeatableRead;
// Set timeout to avoid dead lock conditions.
options.Timeout = new TimeSpan(0, 5, 0);
using (TransactionScope trans = new TransactionScope(TransactionScopeOption.Required, options)) {
// Execute this operation in the transaction.
GetAccountVoucherNuber();
// Call `Complete()` explicitly about transaction commit. Or, it will do rollback.....
trans.Complete();
}
我想你应该在Complete()
上致电TransactionScope
。
Read uncommitted
将do read-lock
and write-lock
in the transaction。换句话说,您的问题是要避免Non-repeatable reads
,而Read uncommitted
或Serializable
隔离级别可以避免此问题。如果您需要避免Phantoms
问题,则需要使用Serializable
隔离级别。不同的隔离级别将具有不同的锁定行为。关于数据库锁,我更喜欢this book, database management systems.
在事务提交或回滚后,它将释放它拥有的所有资源,包括read-locks
和write-locks
。