我们在使用TransactionScope时遇到问题。 TransactionScope为我们提供了非常好的灵活性,可以在我们的数据访问层中使用事务。通过这种方式,我们可以使用隐式或显式的事务。有一些性能再次提升ADO.NET事务,但此时这并不是真正的问题。但是我们有锁定问题。在下面的示例代码中,虽然隔离级别设置为ReadCommitted,但是不可能在表testTable上从其他客户端生成Select SQL语句,直到主事务(在Main方法中)将被提交,因为整个表上存在锁定。我们还尝试在所有方法中仅使用一个连接,但行为相同。我们的DBMS是SQL Server 2008.有什么我们不理解的东西吗?
此致 安东卡尔奇克
请参阅此示例代码:
class Program
{
public class DAL
{
private const string _connectionString = @"Data Source=localhost\fsdf;Initial Catalog=fasdfsa;Integrated Security=SSPI;";
private const string inserttStr = @"INSERT INTO dbo.testTable (test) VALUES(@test);";
/// <summary>
/// Execute command on DBMS.
/// </summary>
/// <param name="command">Command to execute.</param>
private void ExecuteNonQuery(IDbCommand command)
{
if (command == null)
throw new ArgumentNullException("Parameter 'command' can't be null!");
using (IDbConnection connection = new SqlConnection(_connectionString))
{
command.Connection = connection;
connection.Open();
command.ExecuteNonQuery();
}
}
public void FirstMethod()
{
IDbCommand command = new SqlCommand(inserttStr);
command.Parameters.Add(new SqlParameter("@test", "Hello1"));
using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required))
{
ExecuteNonQuery(command);
sc.Complete();
}
}
public void SecondMethod()
{
IDbCommand command = new SqlCommand(inserttStr);
command.Parameters.Add(new SqlParameter("@test", "Hello2"));
using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required))
{
ExecuteNonQuery(command);
sc.Complete();
}
}
}
static void Main(string[] args)
{
DAL dal = new DAL();
TransactionOptions tso = new TransactionOptions();
tso.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required,tso))
{
dal.FirstMethod();
dal.SecondMethod();
sc.Complete();
}
}
}
答案 0 :(得分:19)
我不认为您的问题与.NET TransactionScope概念有任何关系。相反,它听起来像是在描述SQL Server事务的预期行为。此外,更改隔离级别仅影响“数据读取”而不影响“数据写入”。从SQL Server BOL:
“选择事务隔离级别不会影响为保护数据修改而获取的锁定。事务总是会对其修改的任何数据进行独占锁定,并在事务完成之前保持锁定,而不管为此设置的隔离级别如何对于读取操作,事务隔离级别主要定义了对其他事务所做修改的影响的保护级别。“
这意味着您可以通过更改发出SELECT
语句的客户端的隔离级别来阻止阻止行为。 READ COMMITED
隔离级别(默认值)不会阻止阻止。为了防止阻止客户端,您将使用READ UNCOMMITTED
隔离级别,但您必须考虑可能检索已被打开事务更新/插入的记录的可能性(即,如果它们可能会消失交易回滚)。
答案 1 :(得分:9)
谈论交易的好问题。
您的主要方法是保持事务提交。即使您在其他方法中提交,您仍然会在该行上拥有锁。在提交锁定事务之前,您将无法使用READ COMMITTED读取该表,这是预期的。
这是在第一个方法返回后:
第二个方法返回后,您将再向表中添加一个锁。
如果我们从带有SPID(55)的查询窗口执行select语句,您将看到等待状态。
在主要方法trans提交之后,您将获得select语句结果,它只会从我们的select语句查询页面显示 shared lock。
X 表示独占锁定, IX 意图锁定。 You can read more from my blog post about transactions
如果您想在不等待的情况下阅读,可以使用nolock提示。如果要在第一次方法提交后阅读,可以删除该外部范围。