2

在我的场景中,用户向服务器发送请求,然后服务器可以将项目列表上传到数据库。项目列表在 for 循环中上传到数据库,由几个查询组成。将这些项目按顺序添加到数据库中非常重要。

现在,问题是如果用户发出另一个请求,将启动另一组 for 循环,并且项目可能不会以正确的顺序添加到数据库中。(因为将有两个 for 循环将项目添加到数据库中)。

示例:请求 1:1,2,3 请求 2:4,5,6 它们插入数据库的顺序:应该是:1,2,3,4,5,6 但是,可能是:1, 4,2,5,6,3

如果不同的用户发出请求,则没有问题,因为这两个请求将相互排斥。

为了解决这个问题,我可以使用静态方法或使用同步关键字,但我不想在代码中造成瓶颈(其他用户不应该等待访问数据库!)。

或者,使用 for 循环执行多个查询可能是个坏主意?

如何围绕“请求”而不是对象或方法同步我的代码?有设计模式之类的吗?

4

5 回答 5

2

您应该在数据库中强制执行事务。无论您执行何种进程内同步,一旦您拥有多个应用程序服务器实例(几乎所有非平凡应用程序都是这种情况),您的代码就会中断。

例如,您可以在代表用户的行上使用排他行锁。这样,请求将在数据库中序列化,无论您拥有多少应用程序服务器。

于 2013-05-30T20:43:35.303 回答
0

也许不是最好的,但如果我处于你的情况,我会在分离的队列中进行分离的批处理。

示例:您有两个用于队列和详细信息的表:

List_Queue(
    id int identity not null primary key,
    user_id varchar(xx),
    is_processable tinyint default 0,
    is_processing tinyint default 0,
    is_processed tinyint default 0,
)

List_Queue_Detail(
    queue_id int,
    // your rest of data,
    inserted_timestamp datetime
)

List_Queue每次用户提交时都会插入该表。然后在您的示例中,它可能在队列表中有这种记录:

11, user01, 0, 0
12, user01, 0, 0

您的事务将插入到队列详细信息表中。它可能是未排序的,例如:

11, 1, '01.001'
11, 2, '01.021'
12, 4, '01.032'
12, 5, '01.044'
11, 3, '01.055'
12, 6, '01.061'

请注意以秒和毫秒为单位的时间戳。你可以在这里有正常的日期时间。

现在您已完成插入队列详细信息表。假设您现在处于这种队列状态:

11, user01, 0, 0, 0
12, user01, 1, 0, 0

进程 12 早于 11 完成。这是正常情况。现在您的批处理(可能每分钟执行一次)将获得“is_processed = 0 的最小队列 id”,因此您将获得:

11, user01, 0, 0, 0

它不处理请求。如果它可以处理,那么您可以开始将队列详细信息插入到真实的事务表中。不要忘记将请求标记为何is_processing时开始插入。

于 2013-05-31T03:27:14.710 回答
0

听起来您需要发出一个Queue请求才能插入数据库。这样,所有查询都将以您需要的顺序形式执行。

但是,要正确执行此操作,您将需要在单独的线程中执行此操作(无论数据库事务经常阻塞或非常慢,这是一件好事)。

这个解决方案不需要“锁”,并且由于线程仍然会响应,但会保持您对线性的需求。

于 2013-05-30T20:44:02.710 回答
0

如果多个应用程序服务器不是问题,请考虑 StripedLock。它允许您在 ID 上同步,同时只创建有限数量的锁。

https://code.google.com/p/guava-libraries/wiki/StripedExplained

private static Striped<Lock> STRIPPED_LOCK = Striped.lazyWeakLock(64);
try {
    STRIPPED_LOCK.get(id).lock();
    ....stuff....
} finally {
    STRIPPED_LOCK.get(id).unlock();
}

在您的情况下,您可以使用会话 ID(字符串)作为 ID。

于 2013-05-30T20:44:08.003 回答
0

我们这里没有完整的图片,但是既然你说“用户发出另一个请求”,我猜他不等待第一个请求完成?

在这种情况下,您可以考虑使用“命令”模式;查询表示在放入队列中的对象中,程序一次处理队列中的事物。队列中的每个对象都是代表其处理的“命令”。

于 2013-05-30T20:45:15.690 回答