Столкнулся со следующей проблемой. Имеется некий метод,записывающий сущность в бд, примерно такой:
public void Update(Foo foo)
{
UpdateFirstPart(foo.First);
UpdateSecondPart(foo.Second);
UpdateThirdPart(foo.Third);
}
Foo выглядит примерно так:
class Foo
{
public int Id;
public Some1 First;
public Some2 Second;
public Some3 Third;
}
Смысл тут такой: чтобы корректно выполнить обновление нашей сущности, нужно сделать три шага: UpdateFirstPart
, UpdateSecondPart
и UpdateThirdPart
. Проблема в том, что метод Update
может выполняться из разных потоков одновременно. Если используются разные экземпляры foo
, то проблем нет - две сущности параллельно обновляются и всё ок. Проблема возникает, если одновременно обновляются два Foo
с одинаковыми Id
В этом случае изменения в одном потоке могут перетирать изменения другого потока, притом в итоге сохранится часть изменений из первого потока и часть из второго, то есть в результате в бд записывается каша. Во избежание этого вполне логичным кажется поместить код в блокировку:
public void Update(Foo foo)
{
lock(_locker)
{
UpdateFirstPart(foo.First);
UpdateSecondPart(foo.Second);
UpdateThirdPart(foo.Third);
}
}
Всё работает. Но остаётся проблема, заключающаяся том, что эта блокировка работает всегда, в том числе и тогда, когда разные потоки обновляют разные экземпляры Foo
(точнее Foo
с разными Id
)? а мне нужна блокировка тоьлко для тех случаев, когда из двух (или более) потоков происходит вызов Update
для Foo
с одинаковыми Id
. Как это сделать? Может быть у кого-то есть идеи на этот счёт?
А как вам варинт попробовать это выполнить через транзакции?
Это избавит вас от необходимости писать lock-систему.
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// Start a local transaction.
SqlTransaction sqlTran = connection.BeginTransaction();
// Enlist a command in the current transaction.
SqlCommand command = connection.CreateCommand();
command.Transaction = sqlTran;
try
{
// Execute two separate commands.
command.CommandText =
"INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')";
command.ExecuteNonQuery();
command.CommandText =
"INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')";
command.ExecuteNonQuery();
// Commit the transaction.
sqlTran.Commit();
Console.WriteLine("Both records were written to database.");
}
catch (Exception ex)
{
// Handle the exception if the transaction fails to commit.
Console.WriteLine(ex.Message);
try
{
// Attempt to roll back the transaction.
sqlTran.Rollback();
}
catch (Exception exRollback)
{
// Throws an InvalidOperationException if the connection
// is closed or the transaction has already been rolled
// back on the server.
Console.WriteLine(exRollback.Message);
}
}
}
Виртуальный выделенный сервер (VDS) становится отличным выбором
У меня есть около десяти тысяч строчек в таблице следующего формата:
Здравствуйте, помогите пожалуйста решить мою задачуУ меня есть три таблицы в базе данных: Материк, Страна, Город
Раскрывать элемент диаграммы по которому кликнулиНа входе такой массив, где child - это это те элементы, которые надо раскрыть