Вместо того, чтобы сразу отправлять сообщения в БД после их извлечения из очереди, держите список ожидающих сообщений в памяти. Когда вы получаете A или B, проверьте, есть ли соответствующий вариант в списке. Если это так, отправьте их оба (в правильном порядке) в базу данных и удалите соответствующий из списка. В противном случае просто добавьте новое сообщение в этот список.
Если проверка совпадения слишком дорогая задача для сериализации - я предполагаю, что вы используете многопоточность по какой-то причине - вы можете использовать другой поток для обработки списка. Существующие несколько потоков читают, немедленно отправляют большинство сообщений в БД, но откладывают As и B в список (потокобезопасный). Фоновый поток просматривает этот список, находя совпадающие A и B, и когда он находит их, он отправляет их в правильном порядке (и удаляет их из списка).
Суть в том, что, поскольку вы удаляете элементы из очереди с несколькими потоками, вам придется где-то сериализоваться, чтобы обеспечить порядок. Хитрость заключается в том, чтобы свести к минимуму количество раз и продолжительность времени, которое вы проводите взаперти в последовательном коде.
Также может быть что-то, что вы могли бы сделать на уровне базы данных, с помощью триггеров или чего-то еще, чтобы изменить порядок записей при обнаружении этой ситуации. Боюсь, я недостаточно знаю программирование БД, чтобы помочь.
ОБНОВЛЕНИЕ: Предполагая, что сообщения содержат некоторый идентификатор, который позволяет связать сообщение «A» с правильным связанным сообщением «B», следующий код гарантирует, что A будет в базе данных перед B. Обратите внимание, что он не гарантирует, что они являются смежными записи в базе данных — между A и B могут быть другие сообщения. Кроме того, если по какой-то причине вы получаете A или B, но никогда не получаете совпадающее сообщение другого типа, этот код приведет к утечке памяти, поскольку он зависает на несовпадающем сообщении. навсегда.
(Вы можете выделить эти два «заблокированных» блока в одну подпрограмму, но я оставлю это так для ясности в отношении A и B.)
static private object dictionaryLock = new object();
static private Dictionary<int, MyMessage> receivedA =
new Dictionary<int, MyMessage>();
static private Dictionary<int, MyMessage> receivedB =
new Dictionary<int, MyMessage>();
public void MessageHandler(MyMessage message)
{
MyMessage matchingMessage = null;
if (IsA(message))
{
InsertIntoDB(message);
lock (dictionaryLock)
{
if (receivedB.TryGetValue(message.id, out matchingMessage))
{
receivedB.Remove(message.id);
}
else
{
receivedA.Add(message.id, message);
}
}
if (matchingMessage != null)
{
InsertIntoDB(matchingMessage);
}
}
else if (IsB(message))
{
lock (dictionaryLock)
{
if (receivedA.TryGetValue(message.id, out matchingMessage))
{
receivedA.Remove(message.id);
}
else
{
receivedB.Add(message.id, message);
}
}
if (matchingMessage != null)
{
InsertIntoDB(message);
}
}
else
{
// not A or B, do whatever
}
}
person
Bruce
schedule
30.05.2009