所以,我们一直有这些死锁问题,我想在一个简单的代码片段复制此。基本上,我们在进行一些处理之前先登录我们的数据库,然后更新结果。死锁在单台无交易(?)上更新或插入语句
数据库是Sybase ASE的15.7,使用驱动程序的Adaptive Server Enterprise ODBC驱动程序(v15.05)。代码是C#4.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);
}
}
两个测试和测试2抛出随机死锁例外。我并不明确地启动事务,表和查询都很简单,任何人都可以解释发生了什么以及如何避免这个问题?
谢谢!
编辑:本次测试的情况下,其实并不是真的重现问题,我编辑这个,因为我有,当更新设置一个更大尺寸的VARCHAR列发生死锁的感觉。
贾森mentionned,僵局可能会从PK索引的更新到来。一个可能的原因可能是查询锁定表,意识到页面不够用,将行移动到新页面,然后尝试锁定索引以更新,同时在页面上持有锁定时,另一个查询从查询索引开始,然后要求在页面上锁定。
为了测试完整性,如果您进行明确的事务处理,会发生什么情况? – Ralf
我的猜测是它与此相关:http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.dc20021_1251/html/locking/locking7.htm。查看最后一段'在很多情况下,由所有页锁定导致的并发问题来自索引页锁,而不是数据页本身的锁。 –
@Ralf:我在之前的测试中失败了(对于垃圾邮件抱歉),但行为与显式事务声明基本相同。 – vpi