2011-12-29 31 views
1

我有以下问题:多个应用程序的条件的同步请求

我有一个多线程的服务器端应用程序,其中每个请求执行一个新的线程(标准情况)。根据这个请求,应用程序检查是否已将数据缓存到数据库中。如果是的话,它会提取它并将其发送回客户端。如果不是,则称远程服务响应存储在数据库中,然后提取返回给客户端。

该服务需要一段时间来计算数据,并且由于对我的应用程序的请求是异步执行的,所以我陷入了一个检查数据库请求的陷阱,看到里面什么都没有,然后调用服务。同时,另一个具有相同输入的请求会检查数据库,并且由于该服务需要一段时间,所以仍然没有任何内容......因此它会启动另一个服务调用。结果,数据被写入到DB两次,这依赖于它的唯一性(不能有两个记录具有相同的数据),从而导致任何成功操作。

我应该选择什么解决方案? 一个想法是将特定的UNIQUE字段约束放在数据库中。这样,即使应用程序尝试写入两次,数据库也会简单地拒绝它,并且应用程序将抛出异​​常。但是,该服务仍将被执行多次。

我想到的另一个解决方案是同步调用Web服务的方法。这样,每个连续的对我的应用程序的请求都会在前一个操作完成之前放入等待的堆栈中。这样,如果另一个具有相同输入数据的请求进入,而第一个请求仍在等待远程服务的结果,它将等待操作完成。然后,当第二个请求检查数据库时,数据已经存在,并且不需要再次调用该服务。这也将防止在数据库中有多个相同的记录。问题在于我的服务器应用程序的速度将不可避免地降低,因为每个请求都必须等待,即使是通常不应该的请求(那些据说我们已经在数据库中已经有数据的请求)

其他建议?我被卡住了。我怎样才能实现某种条件同步?

回答

1

你可以只同步计算部分,即使用双重检查锁定:你所描述的样子典型的高速缓存使用情况

boolean dataExists = checkDB(); 
if(!dataExists) { 
    synchronized(someSharedObject) { 
    //another thread might have been waiting too and now has put the data into the DB 
    //thus check again 
    if(!checkDB()) { 
     calculateDataAndWriteToDB(); 
    } 
    } 
} 
//do whatever you want with the existing data 
+0

您的someSharedObject应该是来自endUser input的输入。否则它是很好的接近/ – 2011-12-29 07:58:43

0

使用案例。在缓存中,数据通常有一些关键和价值,其中关键字定义了唯一性。如果其他请求更新数据,它将不会创建新记录,而是使用相同的密钥更新现有的记录。如果你这样做,你付出的代价只是调用服务两次,但不应该影响逻辑。那么是否有理由每次创建新记录而不是更新?

我强烈建议不要在您的用例中使用任何方法同步,因为它会自动使您的解决方案无法在多个框中扩展。

+0

当多线程同时准备要插入的数据并尝试插入if时没有任何意义。当数据已经在数据库中(因此当你知道你可以更新它时),OP不想采取任何行动。 – Thomas 2011-12-29 08:07:52

+0

我同意。您可以使用锁定和其他优化的数量。我描述了最简单的情况。 – 2011-12-29 08:12:26

2

只是实现这个算法:

  • 从DB
  • 获得的数据是否存在的数据,返回数据
  • 如果数据不存在,获得与数据的ID相关联的锁获取/ /阻止呼叫
  • 一旦你有锁,检查数据是否在数据库中,如果是,返回数据。否则,调用服务,并把数据在DB
  • 释放锁

这样,你等待,只有当数据没有在数据库中存在尚未锁定。第一个并发线程获取锁是唯一调用该服务的线程,其他所有线程都从数据库获取数据。

这不应妨碍您正确设计数据库并为数据使用唯一主键。无论如何你仍然需要一个服务器集群。

0

在您的第一种方法中,在数据库中使用UNIQUE字段约束将无法解决您的问题,因为endUser将不得不等待远程服务调用返回,并且资源将被使用。

另一种方法是取消具有相同输入数据的请求,并告诉endUser在一段时间后刷新请求。但这不太好,因为它会增加服务器的停机时间。

所以你离开你的第二个方法。我只是建议你同步你的输入数据。 或者你可以检查一下,如果输入数据是相同的,那么等到请求返回,然后从db读取输出。