Share
Embed
Zup Tech Hour - Race Conditions em Microsserviços: um problema comum em arquiteturas distribuidas
Talk apresentada no Zup Tech Hours no dia 13 de abril de 2023. Discutimos o que é Race Conditions, e heurística para la identifica e exploramos 3 soluções, sendo elas @Syncronized da JVM, Pessimistic Locking e Optimistic Locking.
Ficou interessado?
Assista nesse endereço: https://www.youtube.com/live/80I5zv1sDHo?feature=share
Jordi Henrique Silva
April 14, 2023
Transcript
191 slides
-
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
E se mais de um usuário tentar reservar a mesma
poltrona simultaneamente? -
João Maria select p.* from poltrona p where id =
1 select p.* from poltrona p where id = 1 -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: João
Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: João
Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: João
Maria update poltrona set reservado = true, reservadoPara = ‘joao’ where id = 1 select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: João
Maria update poltrona set reservado = true, reservadoPara = ‘joao’ where id = 1 select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: update poltrona set reservado = true, reservadoPara = ‘maria’ where id = 1 -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao João Maria update poltrona set reservado = true, reservadoPara = ‘joao’ where id = 1 select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: update poltrona set reservado = true, reservadoPara = ‘maria’ where id = 1 -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao João Maria Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: maria update poltrona set reservado = true, reservadoPara = ‘joao’ where id = 1 select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: update poltrona set reservado = true, reservadoPara = ‘maria’ where id = 1 1 linha atualizada -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao João Maria Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: maria update poltrona set reservado = true, reservadoPara = ‘joao’ where id = 1 select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: update poltrona set reservado = true, reservadoPara = ‘maria’ where id = 1 1 linha atualizada -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { //read val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") //process if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; //write manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { //read val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") //process if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; //write manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { //read val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") //process if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; //write manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { //read val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") //process if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; //write manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { //read val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") //process if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; //write manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Syncronized @Transactional @Post fun
reservar(@PathVariable id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Syncronized @Transactional @Post fun
reservar(@PathVariable id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
POST /poltronas/1/reservas HTTP 200 HTTP 422, “Poltrona indisponível” Thread 1
Thread 2 POST /poltronas/1/reservas -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Syncronized @Transactional @Post fun
reservar(@PathVariable id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") //RESTANTE DO CODIGO OMITIDO } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Syncronized @Transactional @Post fun
reservar(@PathVariable id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id, PESSIMISTIC_WRITE) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") //RESTANTE DO CODIGO OMITIDO } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Syncronized @Transactional @Post fun
reservar(@PathVariable id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id, PESSIMISTIC_WRITE) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") //RESTANTE DO CODIGO OMITIDO } } -
João Maria select p.* from poltrona p where id =
1 for update -
João Maria select p.* from poltrona p where id =
1 for update select p.* from poltrona p where id = 1 for update -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: João
Maria select p.* from poltrona p where id = 1 for update select p.* from poltrona p where id = 1 for update -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: João
Maria select p.* from poltrona p where id = 1 for update select p.* from poltrona p where id = 1 for update -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: João
Maria select p.* from poltrona p where id = 1 for update select p.* from poltrona p where id = 1 for update -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: João
Maria update poltrona set reservado = true, reservadoPara = ‘joao’ where id = 1 select p.* from poltrona p where id = 1 for update select p.* from poltrona p where id = 1 for update -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: João
Maria COMMIT update poltrona set reservado = true, reservadoPara = ‘joao’ where id = 1 select p.* from poltrona p where id = 1 for update select p.* from poltrona p where id = 1 for update -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao João Maria COMMIT update poltrona set reservado = true, reservadoPara = ‘joao’ where id = 1 select p.* from poltrona p where id = 1 for update select p.* from poltrona p where id = 1 for update -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao João Maria Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao COMMIT update poltrona set reservado = true, reservadoPara = ‘joao’ where id = 1 select p.* from poltrona p where id = 1 for update select p.* from poltrona p where id = 1 for update -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Syncronized @Transactional @Post fun
reservar(@PathVariable id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id, PESSIMISTIC_WRITE) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
Se houver alto volume de requisições causando alta espera por
acesso da linha? -
@Entity class Poltrona( @field:Column(nullable = false) val descricao: String, @field:Column(nullable
= false) var reservadoPara: String, @field:Column(nullable = false) var reservado: Boolean = false @field:Version var version: Long ) { @Id @GeneratedValue var id: Long? = null; } -
@Entity class Poltrona( @field:Column(nullable = false) val descricao: String, @field:Column(nullable
= false) var reservadoPara: String, @field:Column(nullable = false) var reservado: Boolean = false, var version: Long ) { @Id @GeneratedValue var id: Long? = null; } -
@Entity class Poltrona( @field:Column(nullable = false) val descricao: String, @field:Column(nullable
= false) var reservadoPara: String, @field:Column(nullable = false) var reservado: Boolean = false, @field:Version var version: Long ) { @Id @GeneratedValue var id: Long? = null; } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Syncronized @Transactional @Post fun
reservar(@PathVariable id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id, PESSIMISTIC_WRITE) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Syncronized @Transactional @Post fun
reservar(@PathVariable id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Syncronized @Transactional @Post fun
reservar(@PathVariable id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; manager.merge(poltrona); return ok(); } } -
update poltrona set reservado = true, reservadoPara = :user where
id = :poltronaId -
update poltrona set version = 1, reservado = true, reservadoPara
= :user where id = :poltronaId and version = 0 -
João Maria select p.* from poltrona p where id =
1 select p.* from poltrona p where id = 1 -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version:
0 João Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version:
0 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 João Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version:
0 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 João Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version:
0 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 update poltrona set version = 1, reservado = true, reservadoPara = ‘joao’ where id = 1 and version = 0 João Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao version: 1 update poltrona set version = 1, reservado = true, reservadoPara = ‘joao’ where id = 1 and version = 0 João Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao version: 1 update poltrona set version = 1, reservado = true, reservadoPara = ‘joao’ where id = 1 and version = 0 João Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao version: 1 update poltrona set version = 1, reservado = true, reservadoPara = ‘maria’ where id = 1 and version = 0 update poltrona set version = 1, reservado = true, reservadoPara = ‘joao’ where id = 1 and version = 0 João Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao version: 1 update poltrona set version = 1, reservado = true, reservadoPara = ‘maria’ where id = 1 and version = 0 update poltrona set version = 1, reservado = true, reservadoPara = ‘joao’ where id = 1 and version = 0 João Maria select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
1 linha atualizada Poltrona -------------- id: 1, descriçao: A3 reservado:
false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: joao version: 1 update poltrona set version = 1, reservado = true, reservadoPara = ‘maria’ where id = 1 and version = 0 update poltrona set version = 1, reservado = true, reservadoPara = ‘joao’ where id = 1 and version = 0 João Maria OptimisticLockException select p.* from poltrona p where id = 1 select p.* from poltrona p where id = 1 -
João POST /poltronas/1/reservas select p.* from poltrona p where id
= 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 -
João POST /poltronas/1/reservas select p.* from poltrona p where id
= 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 update poltrona set version = 1, reservado = true, reservadoPara = ‘maria’ where id = 1 and version = 0 -
João POST /poltronas/1/reservas select p.* from poltrona p where id
= 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 update poltrona set version = 1, reservado = true, reservadoPara = ‘maria’ where id = 1 and version = 0 Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: maria version: 1 -
João POST /poltronas/1/reservas select p.* from poltrona p where id
= 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 update poltrona set version = 1, reservado = true, reservadoPara = ‘maria’ where id = 1 and version = 0 Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: maria version: 1 update poltrona set version = 1, reservado = true, reservadoPara = ‘joao’ where id = 1 and version = 0 -
João POST /poltronas/1/reservas select p.* from poltrona p where id
= 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 update poltrona set version = 1, reservado = true, reservadoPara = ‘maria’ where id = 1 and version = 0 Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: maria version: 1 update poltrona set version = 1, reservado = true, reservadoPara = ‘joao’ where id = 1 and version = 0 OptimisticLockException -
João POST /poltronas/1/reservas select p.* from poltrona p where id
= 1 Poltrona -------------- id: 1, descriçao: A3 reservado: false reservadoPara: version: 0 update poltrona set version = 1, reservado = true, reservadoPara = ‘maria’ where id = 1 and version = 0 Poltrona -------------- id: 1, descriçao: A3 reservado: true reservadoPara: maria version: 1 update poltrona set version = 1, reservado = true, reservadoPara = ‘joao’ where id = 1 and version = 0 OptimisticLockException HTTP 500 -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; try { manager.merge(poltrona); }catch (ex: OptimisticLockException){ throw HttpStatusException(CONFLICT,"Impossivel realizar a reserva, tente novamente.") } return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; try { manager.merge(poltrona); }catch (ex: OptimisticLockException){ throw HttpStatusException(CONFLICT,"Impossivel realizar a reserva, tente novamente.") } return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; try { manager.merge(poltrona); }catch (ex: OptimisticLockException){ throw HttpStatusException(CONFLICT,"Impossivel realizar a reserva, tente novamente.") } return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; try { manager.merge(poltrona); }catch (ex: OptimisticLockException){ throw HttpStatusException(CONFLICT,"Impossivel realizar a reserva, tente novamente.") } return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> { val poltrona = manager.find(Poltrona::class.java, id) ?: throw HttpStatusException(NOT_FOUND, "Poltrona não existente.") if (poltrona.isReservada()) { throw HttpStatusException(UNPROCESSABLE_ENTITY, "Poltrona indisponivel") } poltrona.reservadoPara = usuario; poltrona.reservado = true; try { manager.merge(poltrona); }catch (ex: OptimisticLockException){ throw HttpStatusException(CONFLICT,"Impossivel realizar a reserva, tente novamente.") } return ok(); } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> {...} @Error fun errorHandler(request: HttpRequest<*>, ex: OptimisticLockException): HttpResponse<*> { return HttpResponse.status<Any>(CONFLICT, ex.message) } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> {...} @Error fun errorHandler(request: HttpRequest<*>, ex: OptimisticLockException): HttpResponse<*> { return HttpResponse.status<Any>(CONFLICT,"Impossivel realizar a reserva, tente novamente.") } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> {...} @Error fun errorHandler(request: HttpRequest<*>, ex: OptimisticLockException): HttpResponse<*> { return HttpResponse.status<Any>(CONFLICT,"Impossivel realizar a reserva, tente novamente.") } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> {...} @Error fun errorHandler(request: HttpRequest<*>, ex: OptimisticLockException): HttpResponse<*> { return HttpResponse.status<Any>(CONFLICT,"Impossivel realizar a reserva, tente novamente.") } } -
@Controller("/api/v1/poltronas/{id}/reservas") class ReservaPoltronaController(val manager: EntityManager) { @Transactional @Post fun reservar(@PathVariable
id: Long, @QueryValue usuario: String): HttpResponse<Void> {...} @Error fun errorHandler(request: HttpRequest<*>, ex: OptimisticLockException): HttpResponse<*> { return HttpResponse.status<Any>(CONFLICT,"Impossivel realizar a reserva, tente novamente.") } } -
Pessimistic Locking Estratégia: Evitar Conflitos Quando utilizar: alto índice de
conflitos, ambientes altamente concorrentes Vantagem: Aumento da consistência Desvantagem: Pode gerar alto nível de contenção levando a queda de produtividade das transações -
Pessimistic Locking Estratégia: Evitar Conflitos Quando utilizar: alto índice de
conflitos, ambientes altamente concorrentes Vantagem: Aumento da consistência Desvantagem: Pode gerar alto nível de contenção levando a queda de produtividade das transações -
Pessimistic Locking Estratégia: Evitar Conflitos Quando utilizar: alto índice de
conflitos, ambientes altamente concorrentes Vantagem: Aumento da consistência Desvantagem: Pode gerar alto nível de contenção levando a queda de produtividade das transações -
Pessimistic Locking Estratégia: Evitar Conflitos Quando utilizar: alto índice de
conflitos, ambientes altamente concorrentes Vantagem: Não exige mudanças no codigo Desvantagem: Pode gerar alto nível de contenção levando a queda de produtividade das transações -
Optimistic Locking Estratégia: Detectar Conflitos Quando utilizar: baixo índice de
conflitos, ambientes razoavelmente concorrentes Vantagem: Menor tempo de bloqueio, menor contenção de transações Desvantagem: em ambientes concorrentes pode gerar alto custo computacional, dado ao grande numero de rollbacks em transações -
Optimistic Locking Estratégia: Detectar Conflitos Quando utilizar: baixo índice de
conflitos, ambientes razoavelmente concorrentes Vantagem: Menor tempo de bloqueio, menor contenção de transações Desvantagem: em ambientes concorrentes pode gerar alto custo computacional, dado ao grande numero de rollbacks em transações -
Optimistic Locking Estratégia: Detectar Conflitos Quando utilizar: baixo índice de
conflitos, ambientes razoavelmente concorrentes Vantagem: Menor tempo de bloqueio, menor contenção de transações Desvantagem: em ambientes concorrentes pode gerar alto custo computacional, dado ao grande numero de rollbacks em transações -
Optimistic Locking Estratégia: Detectar Conflitos Quando utilizar: baixo índice de
conflitos, ambientes razoavelmente concorrentes Vantagem: Menor tempo de bloqueio, menor contenção de transações Desvantagem: em ambientes concorrentes pode gerar alto custo computacional, dado ao grande numero de rollbacks em transações -
Outras estratégias que os Bancos de dados oferecem para lidar
com problemas de concorrência -
Se você usa o Banco de dados ... ... apenas
como repositório. VOCÊ ESTA SUB-UTILIZANDO!