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.
- 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 ...