Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# update或insert语句中没有事务的单个表上的死锁_C#_Sap Ase_Database Deadlocks - Fatal编程技术网

C# update或insert语句中没有事务的单个表上的死锁

C# update或insert语句中没有事务的单个表上的死锁,c#,sap-ase,database-deadlocks,C#,Sap Ase,Database Deadlocks,因此,我们一直存在这些死锁问题,我试图在一个简单的代码片段中复制这些问题。基本上,我们是在进行某些处理之前登录数据库,并在处理之后使用结果进行更新 数据库是Sybase ASE 15.7,使用的驱动程序是Adaptive Server Enterprise ODBC驱动程序v15.05。代码是C4.0 我用于复制问题的代码如下所示: 数据库: create table dbo.test_deadlock_t( id int identity, col1 int not null,

因此,我们一直存在这些死锁问题,我试图在一个简单的代码片段中复制这些问题。基本上,我们是在进行某些处理之前登录数据库,并在处理之后使用结果进行更新

数据库是Sybase ASE 15.7,使用的驱动程序是Adaptive Server Enterprise ODBC驱动程序v15.05。代码是C4.0

我用于复制问题的代码如下所示:

数据库:

create  table dbo.test_deadlock_t(
id   int  identity,
col1   int  not null,
col2   varchar(255)  not null,
constraint test_deadl_id_pk primary key clustered ( id ))
alter table test_deadlock_t lock allpages
C忽略一些声明性代码

using System.Data.Odbc;

public const string cmdInsert = "INSERT INTO test_deadlock_t (col1, col2) VALUES (1, 'test') SELECT @@identity";
public const string cmdUpdate = "UPDATE test_deadlock_t SET col1 = 3, col2 = 'aaaaaaaa' WHERE id = {0}";

public static void Test()
{
    Task[] tasks = new Task[threadCount];
    for (int ii = 0; ii < threadCount; ii++)
    {
        tasks[ii] = Task.Factory.StartNew(() => InsertThenUpdate());
    }
    Task.WaitAll(tasks);
}

public static void Test2()
{
    Task[] tasks = new Task[threadCount];
    for (int ii = 0; ii < threadCount; ii++)
    {
        int ii_copy = ii;
        tasks[ii_copy] = Task.Factory.StartNew(() => Update(ii_copy));
    }
    Task.WaitAll(tasks);
}

public static void InsertThenUpdate()
{
    using (OdbcConnection connection = new OdbcConnection(connectionString))
    {
        connection.Open();
        OdbcCommand command = new OdbcCommand(cmdInsert, connection);
        int result = (int)(command.ExecuteScalar() as decimal?).Value;
        Update(result);
    }
}

public static void Update(int id)
{
    using (OdbcConnection connection = new OdbcConnection(connectionString))
    {
        connection.Open();
        OdbcCommand command = new OdbcCommand(String.Format(cmdUpdate, id), connection);
        int result = command.ExecuteNonQuery();
        Console.WriteLine("Update result : " + result);
    }
}
Test和Test2都会抛出随机死锁异常。我不是在明确地启动事务,表和查询尽可能简单,有人能解释发生了什么以及如何避免这个问题吗

谢谢

编辑:这个测试用例实际上并没有再现这个问题,我正在编辑它,因为我感觉当更新将varchar列设置为更大的大小时,死锁就会发生


正如Jason提到的,死锁可能来自PK索引的更新。一个可能的原因可能是,当另一个查询开始查询索引,然后要求锁定页面时,查询锁定了表,意识到页面不够用,将行移动到新页面,然后尝试锁定要更新的索引,同时保持页面上的锁。

我不确定这对将来的任何人都有帮助,但未回答的问题很糟糕,所以我发现:

只有当更新使行变长时,才会出现问题。Jason正确地提出锁可能来自索引。在进一步分析日志后,我们得出以下结论:

Deadlock Id 29756: Process (Familyid 0, Spid 282) was waiting for a 'exclusive page' lock on page 26700113 of table 'test_deadlock_t' in database 'xxx' but process (Familyid 0, Spid 1051) already held a 'exclusive page' lock on it.
Deadlock Id 29756: Process (Familyid 0, Spid 1051) was waiting for a 'exclusive page' lock on page 29892374 of table 'test_deadlock_t' , indid 1 in database 'xxx' but process (Familyid 0, Spid 282) already held a 'exclusive page' lock on it.
indid 1表示主键

我的理解是sybase将页面锁定在它想要进行更新的地方。同时,select以某种方式请求对索引进行锁定。然后,更新会意识到页面对于更新的行来说太小,因此它会尝试移动页面,并请求对索引进行锁定。但是select已经有一个锁,并且select想要访问同一页


如果有人对正在发生的事情有更好的了解,我很高兴知道。在我们的例子中,使用固定长度字段解决了这个问题。

为了测试的完整性,如果执行显式事务处理,会发生什么情况?我猜这与此有关:。请参阅最后一段“在许多情况下,所有页面锁定导致的并发问题都是由索引页面锁引起的,而不是数据页面上的锁本身。”@Ralf:我在之前的测试中失败了,很抱歉垃圾邮件,但行为与显式事务声明基本相同。