我是静止的新手,正在尝试编写一个简单的rest api,将一些量从一个源转移到另一个源。我没有数据库,使用地图作为数据源。我的服务只是检查源是否有足够的金额可转移,如果是,那么我会同时更新源和目标。问题是我同时关注多个请求。因为当有多个请求时,它们都可以使用相同的源值同时进行验证,这会导致错误的行为。
示例:来源有金额100,并且有2个请求以金额70进行转帐。处理这两个请求时,它们都同时检查了来源有金额100,然后可以执行转帐。
1)我的资源:
public class MyResource {
@Inject
TransferService transferService;
@POST
@Produces(MediaType.APPLICATION_JSON)
public Transfer transfer(Transfer transfer){
return transferService.transfer(transfer);
}
}
2)来源POJO
public class Source {
private String sourceId;
private double balance;
....
}
3)源服务
public class SourceServiceImp implements SourceService {
@Override
public Source getSource(String sourceId) {
Source source = EmbeddedSources.getSource(sourceId);
return source;
}
public boolean deposit(String sourceId, double amount ){
Source source = getSource(sourceId);
source.setBalance(source.getBalance() + amount);
EmbeddedSources.updateSource(sourceId, source);
return true;
}
public boolean withdraw(String sourceId, double amount ){
Source source = getSource(sourceId);
source.setBalance(source.getBalance() - amount);
EmbeddedSources.updateSource(sourceId, source);
return true;
}
}
4)TransferService
public class TransferServiceImpl implements TransferService {
private static SourceService sourceService ;
public TransferServiceImpl(SourceService sourceService){
this.sourceService = sourceService;
}
@Override
public Transfer transfer(Transfer transfer) {
Source sourceSource = sourceService.getSource(transfer.getSourceSourceId());
Source destSource = sourceService.getSource(transfer.getDestSourceId());
double amount = transfer.getAmount();
if(isBalanceEnough(sourceSource, destSource, amount)){
sourceService.withdraw(sourceSource.getSourceId(), amount);
sourceService.deposit(destSource.getSourceId(), amount);
}
transfer.setStatus("VALID");
return transfer;
}
}
5)嵌入式数据库
public class EmbeddedSources {
private static Map<String, Source> sourceMap = new ConcurrentHashMap<>();
private static Map<String, Transfer> transferMap = new ConcurrentHashMap<>();
public static Source getSource(String sourceId){
return sourceMap.get(sourceId);
}
public static void updateSource(String sourceId, Source source){
sourceMap.put(sourceId, source);
}
public static void addSource(Source source){
sourceMap.put(source.getSourceId(), source.deepCopy());
}
}
我考虑过使用队列进行请求,但是我认为这不是一个好的解决方案。我也考虑过将volatile用于源类字段,但仍然不能避免对同一sourceId的多次请求。
如何防止此问题并使多个请求的服务安全?