Share
Embed
Race Conditions em Microsserviços: Desmistificando um Problema Comum em Arquiteturas Distribuídas
Os microsserviços são uma realidade na arquitetura de sistemas distribuídos, porém, o aumento da complexidade desses sistemas trouxe novos desafios, em especial na garantia da integridade e consistência dos dados de negócio. Com a crescente adoção de microsserviços, problemas de concorrência, como Race Conditions e Lost Update, se tornaram mais frequentes e podem comprometer a eficiência dos seus sistemas. Nesta talk, vamos explorar as causas que levam a problemas de Race Conditions em microsserviços, assim como heurísticas para identificar e controlar situações de concorrência.
Talk apresentada na trilha de Microsserviços II no TDC CONNECTIONS 2023.
Talk apresentada na Weekly II no TDC CONNECTIONS 2023.
Jordi Henrique Silva
March 24, 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!