Camada Zero · 24 · Transações & ACID

Transferir dinheiro são duas operações: tirar de um, pôr no outro. Se o sistema cair entre as duas, o dinheiro some ou duplica. A transação existe pra que isso nunca aconteça. Roda aqui embaixo com e sem transação e olha o total de dinheiro no fim.
Conta A
R$ 100
Conta B
R$ 50
Estado: ocioso
Pronto. Roda uma transferência normal, depois liga a falha no meio e compare o total final com e sem transação.
0Operações
0Commitadas
0Revertidas
R$ 150Total no sistema
SimInvariante preservada
O total de dinheiro (R$ 150) é uma invariante: transferir muda quem tem, nunca o total. Sem transação, uma falha entre o débito e o crédito quebra essa invariante e o dinheiro evapora. A transação garante que as duas operações são uma coisa só: ou as duas valem, ou nenhuma.
A · AtomicidadeTudo ou nada. Falhou no meio, desfaz tudo (rollback).
C · ConsistênciaVai de um estado válido a outro, respeitando as invariantes (total, constraints).
I · IsolamentoTransações concorrentes não enxergam o meio uma da outra.
D · DurabilidadeDepois do commit, sobrevive a um crash (graças ao log, aula 23).

Transação em Go (database/sql)

func transferir(db *sql.DB, de, para string, valor int) error {
    tx, err := db.Begin()
    if err != nil { return err }
    defer tx.Rollback() // no-op se já houve Commit

    _, err = tx.Exec("UPDATE contas SET saldo = saldo - $1 WHERE id = $2", valor, de)
    if err != nil { return err } // o defer reverte o débito

    _, err = tx.Exec("UPDATE contas SET saldo = saldo + $1 WHERE id = $2", valor, para)
    if err != nil { return err }

    return tx.Commit() // só aqui o dinheiro "existe" de verdade
}

🧠 Desafio — Transações & ACID

Roda a transferência com e sem transação (e com falha no meio) antes de responder. As duas últimas são de reflexão: escreve a sua e só então revela o modelo.

🔧 Prática — ache o bug

Essa transferência quebra a atomicidade. Clica na linha do bug.