我开发了一个典型的企业应用程序,负责将客户配置到第 3 方系统。该系统有一个限制,即只有一个线程可以处理某个客户。所以我们添加了一个简单的锁定机制,@Singleton
其中包含一个Set
当前正在进行的 customerIds。每当有新的供应请求出现时,它首先检查 this Set
。如果 customerId 存在,它会等待,否则将其添加到Set
并进入处理。
最近决定,这个应用程序将部署在集群中,这意味着这种锁定方法不再有效。我们提出了一个使用 DB 进行锁定的解决方案。我们创建了一个包含 customerIds 的单列表(它也有一个唯一的约束)。当一个新的供应请求到来时,我们开始一个事务并尝试用 customerId 锁定行SELECT FOR UPDATE
(如果 customerId 还不存在,我们插入它)。之后,我们开始配置客户,完成后,我们提交事务。概念有效,但我在交易方面遇到问题。目前我们有一个类CustomerLock
和方法来处理添加和删除add()
customerIds 。我想将此类转换为具有 bean 管理事务的无状态 EJB。remove()
Set
add()
方法将启动事务并锁定行,而remove()
方法将提交事务并因此解锁行。但似乎事务的开始和结束必须以相同的方法发生。有没有办法使用我描述的方法,或者我必须修改逻辑以便事务以相同的方法开始和结束?
客户锁类:
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class CustomerLock {
@Resource
private UserTransaction tx;
public void add(String customerId) throws Exception {
try {
tx.begin();
dsApi.lock()
} catch (Exception e) {
throw e;
}
}
public void remove(String customerId) throws Exception {
try {
tx.commit();
} catch (Exception e) {
throw e
}
}
}
CustomerProvisioner 类摘录:
public abstract class CustomerProvisioner {
...
public void execute(String customerId) {
try {
customerLock.add(customerId);
processing....
customerLock.remove(customerId);
} catch (Exception e) {
logger.error("Error", e);
}
}
...
}
StandardCustomerProvisioner 类:
@Stateless
public class StandardCustomerProvisioner extends CustomerProvisioner {
...
public void provision(String customerId) {
// do some business logic
super.execute(customerId);
}
}