Concurrencia y transacciones - script - ejemplo
From Ibbddunq
Contents |
El esquema de BD
encomienda <nroEncomienda, cliente, peso> servicio <nroServicio, origen, destino, disponible, cargaTotal> encomiendaEnServicio <nroServicio, nroEncomienda>
agregarEncomienda
procedure agregarEncomienda(elCliente, elPeso, elServicio)
begin
declare nroNuevaEnco integer;
declare disponibleNuevo integer;
declare cantEncomiendas integer;
select max(nroEncomienda) + 1 from encomienda into nroNuevaEnco;
select disponible - elPeso from servicio
where nroServicio = elServicio
into disponibleNuevo;
select count(*) from encomiendaEnServicio where nroServicio = elServicio
into cantEncomiendas;
if (cantEncomiendas < 10) then
insert into encomienda (nroEncomienda, cliente, peso)
values (nroNuevaEnco, elCliente, elPeso);
insert into encomiendaEnServicio (nroEncomienda, nroServicio)
values (nroNuevaEnco, elServicio);
update servicio set disponible = disponibleNuevo
where nroServicio = elServicio;
end if;
end
con este stored procedure se puede
- mostrar un schedule de dos tx en el que el disponible de un servicio quede mal.
- llegar a la conclusión de qué condición deben tener dos ejecuciones concurrentes para que pueda haber anomalías de concurrencia: que estén agregando encomiendas en el mismo servicio.
- ver cómo tiene que ser un schedule para ser "malo": ambos deben leer el disponibleNuevo antes de que cualquiera de ellos haga update.
- tal vez,
- corregir el update seteando disponible - elPeso, y sacando el select del servicio de arriba. Aclarar que toma el disponible en el momento que se ejecuta el update. Llegar a la conclusión de que se arregla la anomalía observada antes ...
- ... pero queda otra: puedo poner 11 encomiendas en un servicio. Esta la vamos a tener que solucionar reservando un recurso, o sea, que sea válido que yo diga "yo agarro un servicio y hasta que yo no termine nadie puede hacer nada con el servicio"
pasarPeso
procedure pasarPeso (servDesde, servHacia, cuanto)
begin
declare nuevoDisponible;
start transaction
update servicio set disponible = disponible + cuanto
where nroServicio = servDesde;
select disponible - cuanto from servicio
where nroServicio = servHacia
into nuevoDisponible;
if (nuevoDisponible >= 0) then
update servicio set disponible = disponible - cuanto
where nroServicio = servHacia;
commit;
else
rollback;
end if;
end
cantidadServiciosADestinos
ya viene ...
