弹簧启动 - 如何避免并发访问控制器
我们有一个Spring Boot应用程序,该应用程序链接到现场的各种客户端。此应用程序具有一个控制器,该控制器从客户端调用,并与数据库和物理交换机进行交互,以关闭或打开灯。
当两个或多个客户端访问服务器上的 API 时,问题就来了,因为该方法会检查指示灯是打开还是关闭(在 DB 上)以更改其状态。如果指示灯为 OFF,并且 2 个客户端同时调用服务,则第一个客户端打开指示灯并更改 db 上的状态,但第二个客户端也访问指示灯,DB 上的状态为 OFF,但第一个客户端已经调谐了指示灯,因此秒数最终关闭它,以为打开它...也许我的解释有点不清楚,问题是:我能告诉spring在当时访问控制器一个请求吗?
由于下面的答案,我们在切换开关的方法上引入了悲观锁定,但我们继续从客户那里获得200状态...
我们正在使用弹簧靴+冬眠
现在控制器有悲观锁的例外
try {
String pinName = interruttore.getPinName();
// logger.debug("Sono nel nuovo ciclo di
// gestione interruttore");
if (!interruttore.isStato()) { // solo se
// l'interruttore
// è
// spento
GpioPinDigitalOutput relePin = interruttore.getGpio()
.provisionDigitalOutputPin(RaspiPin.getPinByName(pinName));
interruttoreService.toggleSwitchNew(relePin, interruttore, lit); // accendo
interruttore.getGpio().unprovisionPin(relePin);
}
} catch (GpioPinExistsException ge) {
logger.error("Gpio già esistente");
} catch (PessimisticLockingFailureException pe){
logger.error("Pessimistic Lock conflict", pe);
return new ResponseEntity<Sensoristica>(sensoristica, HttpStatus.CONFLICT);
}
toggleSwitchNew
如下
@Override
@Transactional(isolation=Isolation.REPEATABLE_READ)
public void toggleSwitchNew(GpioPinDigitalOutput relePin, Interruttore interruttore, boolean on) {
Date date = new Date();
interruttore.setDateTime(new Timestamp(date.getTime()));
interruttore.setStato(on);
String log = getLogStatus(on) + interruttore.getNomeInterruttore();
logger.debug(log);
relePin.high();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
logger.error("Errore sleep ", e);
}
relePin.low();
updateInterruttore(interruttore);
illuminazioneService.createIlluminazione(interruttore, on);
}
然后,我们在客户端中记录请求状态代码,即使它们是并发的,它们也总是得到200