Assim como na vida real, o mundo da ciência da computação está repleto de concessões. Bancos de dados relacionais não são exceção. Ao interagir com bancos de dados relacionais, enfrentamos o dilema entre consistência de dados e concorrência de transações. A primeira garante que os dados sejam confiáveis, enquanto a segunda garante que bancos de dados relacionais possam realizar transações rapidamente. Ambas são qualidades desejáveis dos bancos de dados relacionais, mas não podemos alcançá-las simultaneamente ao máximo. Hoje, discutirei como níveis de isolamento podem nos ajudar a estruturar nossa tomada de decisão em relação a esse dilema.
Leia Inconsistências
Antes de mergulhar nos níveis de isolamento, vou primeiro apresentar três inconsistências comuns de leitura em bancos de dados relacionais: leitura suja, leitura não repetível e leitura fantasma. São inconsistências de dados causadas por transações concorrentes. Elas são cruciais para entender os níveis de isolamento porque, se estão presentes ou ausentes em um nível de isolamento, determina seu grau de consistência de dados.
Leitura Suja
Uma leitura suja é essencialmente uma leitura de dados não comprometidos. Ela ocorre quando uma transação lê dados modificados por outra transação, mas ainda não comprometidos.
Aqui está um exemplo: Suponha que existam duas transações: T1 e T2. Ambas interagem com a mesma tabela chamada "BankAccount." Essa tabela contém a seguinte linha.

T1 lê a linha acima na tabela Bankaccount, enquanto T2 a modifica.
'''sql -- Declaração SQL do T1: SELECIONAR o saldo DA Conta Bancária ONDE account_number = 88;
'''sql
-- Declaração SQL do T2:
ATUALIZAÇÃO: saldo CONJUNTO da Conta Bancária = 800 ONDE account_number = 88;
Até agora, todo o processo parece uma série de operações inocentes de banco de dados. No entanto, o problema é que, quando T1 lê a linha, T2 já a modificou, mas ainda não comprometeu, o que faz com que T1 acabe lendo dados sujos. Isso pode causar um problema ainda mais sério se usarmos os dados sujos de T1 para operações futuras quando o banco de dados reverter as modificações feitas por T2 devido a algumas falhas.
Leitura Não Repetível
Uma leitura não repetível ocorre quando duas leituras da mesma linha dentro de uma transação têm resultados diferentes. A razão é que outra transação comprometida modificou essa linha após a primeira e antes da segunda leitura da transação anterior.
Aqui está um exemplo: Suponha que existam duas transações: T1 e T2. Ambas interagem com a mesma tabela chamada "Book". Esta tabela contém a seguinte linha.

T1 lê a linha acima na tabela Book duas vezes, enquanto T2 a modifica.
'''sql -- Declaração SQL do T1: SELECIONAR preço DO Livro ONDE id = 1; SELECIONAR o preço DO Livro ONDE id = 1;
'''sql
-- Declaração SQL do T2:
ATUALIZAÇÃO BOOK SET preço = 20 ONDE id = 1;
A primeira leitura de T1 recupera com sucesso o preço original (15) de O Grande Gatsby. Depois, T2 atualiza a linha e modifica o preço antes do início da segunda leitura de T1. No final, a segunda leitura de T1 obtém o preço mais recente (20), resultando na inconsistência de T1 entre suas duas leituras da mesma linha.
Leitura Fantasma
Semelhante a uma leitura não repetível, uma leitura fantasma também é um tipo de inconsistência de leitura dentro da mesma transação. Ela ocorre quando duas leituras idênticas dentro da mesma transação retornam números diferentes de linhas. A razão é que outra transação comprometida inseriu ou excluiu algumas linhas após a primeira e antes da segunda leitura da transação anterior.
Aqui está um exemplo: Suponha que existam duas transações: T1 e T2. Ambas interagem com a mesma tabela chamada "Book". Esta tabela contém a seguinte linha.

T1 lê todas as linhas da tabela Book duas vezes, enquanto T2 insere uma nova linha na tabela Book Table.
'''sql -- Declaração SQL do T1: SELECT * FROM Book; SELECT * FROM Book;
'''sql
-- Declaração SQL do T2:
INSERIR EM Livro (id, título, preço) VALORES (2, 'Orgulho e Preconceito', 20)
A primeira leitura de T1 recupera a única linha (O Grande Gatsby) na tabela de livros. Depois, T2 insere uma nova linha (Orgulho e Preconceito) na tabela de livros antes de começar a segunda leitura de T1. No final, o resultado da segunda leitura de T1 consiste em duas linhas (O Grande Gatsby e Orgulho e Preconceito), incluindo a nova inserida por T2.
Níveis de Isolamento

Em seguida, vamos mergulhar nos quatro níveis de isolamento das transações SQL. Vou começar pelo nível de isolamento mais baixo e examinar o restante em ordem crescente.
Leia Não Comprometido
Leitura Não Comprometida é o nível mais baixo de isolamento. Também corresponde ao nível mais alto de concorrência de transações, não impondo restrições ao acesso e modificação simultânea do banco de dados. Todas as inconsistências de leitura que mencionei acima (leituras sujas, leituras não repetíveis e leituras fantasma) são possíveis.
Leia Comprometido
O Read Commit é o segundo menor nível de isolamento. Ele permite transações concorrentes desde que as transações não leiam dados não comprometidos. Devido a essa restrição, o Read Commit elimina a possibilidade de leituras sujas ao custo da concorrência. No entanto, leituras não repetíveis e leituras fantasma ainda podem ocorrer.
Leitura Repetível
A Leitura Repetível é o segundo nível mais alto de isolamento. Além da restrição imposta pelo Leitura Commitada, a Leitura Repetível bane duas leituras da mesma linha dentro da mesma transação de terem resultados diferentes. Ela alcança essa restrição colocando bloqueios compartilhados em todos os dados lidos por cada instrução em uma transação. O banco de dados não libera os bloqueios compartilhados até que a transação correspondente seja concluída. Como resultado, outras transações não conseguem fazer alterações nos dados travados. Essa restrição adicional diminui ainda mais o nível de concorrência das transações. Graças a essa restrição, a Leitura Repetível torna leituras não repetíveis impossíveis. No entanto, a Leitura Repetível ainda enfrenta o risco de leituras fantasmas.
Serializável
Serializável é o nível de isolamento mais alto. Como seu nome sugere, ele permite que transações ocorram simultaneamente apenas se os resultados produzidos forem os mesmos de se forem executadas em série. Além das restrições impostas pelos dois níveis de isolamento anteriores, ele ainda impede que duas leituras idênticas dentro da mesma transação retornem números diferentes de linhas. Ele alcança essa restrição colocando bloqueios de intervalo no intervalo de dados que correspondem às condições de busca de todas as instruções de uma transação. O banco de dados mantém todos os bloqueios de intervalo antes do término correspondente da transação. Essa restrição reduz a concorrência das transações ao mínimo, mas ajuda o Serializable a alcançar o mais alto nível de consistência dos dados. Todas as três inconsistências de leitura (leituras sujas, leituras não repetíveis e leituras fantasma) estão fora de questão.
Dicas sobre qual nível de isolamento escolher
Agora que cobrimos os quatro níveis de isolamento, alguns de vocês podem perguntar: "qual nível de isolamento devo escolher para meu banco de dados relacional então?" Essa pergunta basicamente se resume a quanta concorrência você está disposto a abrir mão em troca da consistência dos dados.
Leia Não Comprometido
Uma regra prática é evitar usar Read Uncommitted, porque a leitura suja é o tipo mais indesejável de inconsistência de dados. A única exceção é quando o desempenho é muito mais importante do que a consistência dos dados.
Leia Comprometido
Read Committed é o nível padrão de isolamento na maioria dos bancos de dados. Ele oferece um bom equilíbrio entre concorrência e consistência. Se você não tiver certeza de qual isolamento escolher, pode começar com segurança experimentando Read Committed.
Leitura Repetível
A Leitura Repetível oferece ótima consistência de dados à custa da concorrência. A única inconsistência de leitura que afeta esse nível de isolamento é a leitura fantasma. Você deve escolher Leitura Repetível quando valoriza a consistência dos dados em detrimento do desempenho do seu sistema.
Serializável
Serializável possui o mais alto nível de consistência de dados. Em troca, sofre do menor nível de concorrência de transações e, portanto, do pior desempenho. Serializável é uma escolha adequada quando você tem uma política de tolerância zero contra inconsistência de dados, mas lembre-se de que o desempenho do seu sistema sofrerá consequência.
Neste blog, abordei três tipos de inconsistências de leitura (Leitura Suja, Leitura Não Repetível e Leitura Fantasma) e quatro níveis de isolamento (Leitura Não Comprometida, Leitura Confirmada, Leitura Repetível e Serializável). Cada nível de isolamento tolera algumas inconsistências de leitura enquanto proíbe outras. Escolher entre esses níveis de isolamento é essencialmente um equilíbrio entre concorrência e consistência. Espero que este artigo seja útil para você.