如何在现有服务结构中实现“锁定” - 层

时间:2011-02-28 14:27:32

标签: java spring transactions service locking

目前的情况:我有一些服务,有几个典型的服务方法,如create(),remove(),findXy(),...等。现在我想同时阻止两个不同的服务调用,这意味着我想要在第一次输入后锁定我的servicecall,所以第二个客户端(或同一个客户端)只会在第一个客户端完成后立即输入该方法。

出于锁定目的,我们通常使用ReentrantLocks。他们的工作非常好。但现在我怀疑如何实现这些ReentrantLocks,因为我不想在每个方法中插入它们。此外,我们的服务层已经自己定义了它们的事务上下文,这意味着,当我将它们集成到方法本身时,事务已经在锁定发生之前就已经开始了。

public class WorkerServiceServerImpl implements WorkerServiceRemote
{
  private static final ReentrantLock workerLock = new ReentrantLock( true );

  @Autowired
  private WorkerDao                 workerDao;

  @Override
  @Transactional
  public int createWorker( int projectId ) throws RemoteException
  {
    workerLock.lock();//NO GOOD! Transaction already started!

    try
    {
      workerDao.create( projectId );

      //Do some more stuff...
    }
    finally
    {
      workerLock.unlock();//Unlock, next request can be handled!
    }
  }

  ...
}

当然我可以在这个WorkerServiceImpl类之上创建一个ServiceLayer,只是将调用转发给原始服务,但是因为我有30个服务,我想知道,如果有任何全局解决方案来解决这个问题。或者是否可以创建一个在事务开始之前触发的自己的注释?

欢迎任何想法,提前感谢! ymene

编辑:为简单起见,我选择CRUD方法。当然,这些服务调用要先进得多,并且可以在一次调用中调用不同的CRUD方法。

2 个答案:

答案 0 :(得分:2)

关于这种设计,有几点可以提出:

  • 将锁应用于服务方法的需求看起来很奇怪。如果您在并发执行服务方法时遇到一些问题,那么在访问底层数据库时通过正确配置事务来解决它们可能会更好。

  • 必须在unlock()块内调用
  • finally

  • 如果您的服务是单身,则使用ReentrantLock相当于标记您的方法synchronized

  • 您可以创建方面以将同步应用于方法。请参阅7. Aspect Oriented Programming with Spring,尤其是7.2.4.7 Advice ordering

答案 1 :(得分:1)

由于您似乎使用的是Spring,因此可以定义单例LockInterceptor,并在事务拦截器之前将其放入拦截器堆栈中。这个拦截器非常简单:

import org.aopalliance.intercept.*;
public class LockInterceptor implements MethodInterceptor {

    @Override
    public synchronized Object invoke(MethodInvocation mi) throws Throwable {
        return mi.proceed();
    }
}