Сервисная операция MyMethod(int id)
извлекает определенную строку (на основе параметра id
) из одной таблицы БД и непосредственно перед ее возвратом сохраняет это состояние обратно в таблицу.Если два вызова (первый вызов происходит в транзакции T1 , а второй в транзакции T2 ) на MyMethod()
сделаны одновременно, то служба попытается выполнить два вызова одновременно.Поскольку и T1 , и T2 пытаются получить доступ к одной и той же таблице БД, одной из двух транзакций будет предоставлен доступ к ресурсу, в то время как другая должна быть заблокирована до тех пор, пока исходная транзакция не завершится или не прекратит работу.Но вместо этого я получаю исключение Транзакция (ID процесса 54) была заблокирована для ресурсов блокировки другого процесса и была выбрана в качестве жертвы тупика
Я не понимаю причины, по которой возникает исключение взаимоблокировкипоскольку, насколько я могу судить, опасности тупика нет.С одной стороны, две транзакции доступны и работают в разных строках.Почему вместо этого ресурс БД не был заблокирован до тех пор, пока исходная транзакция не была зафиксирована или прервана ?!
Вот код:
[ServiceContract]
public interface IService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void Process(int id);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults=true)]
public class Service : IService
{
string state_Data = "";
[OperationBehavior(TransactionScopeRequired = true)]
public void Process(int id)
{
GetState(id);
Thread.Sleep(6000);
SaveState(id);
}
private void GetState(int id)
{
using (SqlConnection con = new SqlConnection())
{
con.ConnectionString = "data source=localhost; initial catalog=WCF; integrated security=sspi;";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM StateTable WHERE id = @id";
cmd.Parameters.Add("@id", SqlDbType.Int).Value = id;
cmd.Connection = con;
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
state_Data = reader["State"].ToString();
}
}
private bool SaveState(int id)
{
using (SqlConnection con = new SqlConnection())
{
con.ConnectionString = "data source = localhost; initial catalog=WCF; integrated security=sspi;";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "UPDATE StateTable SET State=@State WHERE Id = @id";
cmd.Parameters.Add("@id", SqlDbType.Int).Value = id;
cmd.Parameters.Add("@State", SqlDbType.NVarChar).Value = state_Data;
cmd.Connection = con;
con.Open();
int ret = cmd.ExecuteNonQuery();
return ret == 1;
}
}
}
РЕДАКТИРОВАТЬ:
В случае, если это поможет, вот код клиента:
ПЕРВЫЙ КЛИЕНТ:
ServiceClient proxy = new ServiceClient("WSDualHttpBinding_IService");
using (TransactionScope scope = new TransactionScope())
{
proxy.Process(1);
scope.Complete();
}
ВТОРОЙ КЛИЕНТ:
ServiceClient proxy = new ServiceClient("WSDualHttpBinding_IService");
using (TransactionScope scope = new TransactionScope())
{
proxy.Process(2);
scope.Complete();
}
Спасибо