与其在将消息从队列中取出后立即将它们推送到数据库,不如在内存中保留一个待处理消息的列表。当您获得 A 或 B 时,请检查匹配的是否在列表中。如果是这样,请将它们(以正确的顺序)提交到数据库,并从列表中删除匹配的一个。否则,只需将新消息添加到该列表即可。
如果检查匹配项的任务太昂贵而无法序列化-我假设您出于某种原因正在使用多线程-您可以让另一个线程处理该列表。现有的多个线程读取,立即将大部分消息提交给 DB,但将 As 和 Bs 放在(线程安全)列表中。后台线程通过该列表查找匹配的 As 和 B,并在找到它们时以正确的顺序提交它们(并将它们从列表中删除)。
底线是 - 由于您使用多个线程从队列中删除项目,因此您将不得不在某个地方进行序列化,以确保排序。诀窍是尽量减少锁定在序列码中的次数和时间长度。
您可能还可以在数据库级别使用触发器或其他方式执行某些操作,以便在检测到这种情况时重新排序条目。恐怕我对数据库编程知之甚少,无法提供帮助。
更新:假设消息包含一些 id,可让您将消息“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
}
}