围绕变量进行同步而不是类或方法

时间:2013-05-30 20:39:19

标签: java sql multithreading design-patterns synchronization

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

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

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

如果其他用户发出请求,则没有问题,因为这两个请求将是互斥的。

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

或者,使用for循环执行多个查询也许是一个坏主意?

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

5 个答案:

答案 0 :(得分:2)

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

你可以,例如在代表用户的行上使用独占行锁。这样,请求将在数据库中序列化,并且与您拥有的应用程序服务器数量无关。

答案 1 :(得分:0)

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

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

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

答案 2 :(得分: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。

答案 3 :(得分:0)

我们这里没有完整的图片,但由于您说“用户发出另一个请求”,我认为他不等待第一个请求完成?

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

答案 4 :(得分: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完成。这是正常情况。现在您的批处理(可能每分钟执行一次)将得到`最小队列ID,is_processed = 0',所以你得到:

11, user01, 0, 0, 0

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