Introdução
Em aplicações de fintech, garantir a integridade das transações financeiras é essencial. Problemas como transações incompletas ou dados inconsistentes podem comprometer a confiança dos usuários e a segurança do sistema. Para mitigar esses riscos, podemos usar os conceitos de transações ACID, que garantem operações confiáveis e robustas.
Neste artigo, vou mostrar as propriedades ACID e uma implementação usando NestJS, Prisma e PostgreSQL, utilizando o seguinte modelo de transação:
model Transaction {
id Int @id @default(autoincrement())
userId Int
subTotal Decimal @default(0) @db.Decimal(10, 2)
total Decimal @default(0) @db.Decimal(10, 2)
transactionId String? @unique
order_processor_id String
payment_method PaymentMethod
status TransactionStatus
external_id String
e2e_id String?
error_message String?
created_at DateTime? @default(now())
updated_at DateTime? @updatedAt
customerId Int?
callback_url String?
typeTransaction TypeTransaction
future_balance Decimal @default(0) @db.Decimal(10, 2)
previous_balance Decimal @default(0) @db.Decimal(10, 2)
Customers Customer? @relation(fields: [customerId], references: [id])
user User @relation(fields: [userId], references: [id])
}
Entendendo as Propriedades ACID
1. Atomicidade (Atomicity)
A atomicidade garante que uma transação seja tratada como uma unidade indivisível. Ou todas as operações dentro da transação são executadas com sucesso, ou nenhuma é aplicada. Isso é crucial em aplicações fintech para evitar cenários como debitar uma conta sem creditar o destinatário.
Exemplo:
Imagine transferir fundos entre duas contas:
await this.prisma.$transaction(async (prisma) => {
await prisma.transaction.create({
data: {
userId: fromUserId,
subTotal: amount,
total: amount,
status: 'PENDING',
},
});
await prisma.transaction.create({
data: {
userId: toUserId,
subTotal: amount,
total: amount,
status: 'COMPLETED',
},
});
});
Se a criação de qualquer uma das transações falhar, o sistema garante que nenhuma alteração seja persistida.
2. Consistência (Consistency)
A consistência assegura que o banco de dados transite de um estado válido para outro, sempre preservando regras e restrições definidas.
Exemplo:
Ao criar uma nova transação, todos os campos obrigatórios, como userId
, subTotal
e status
, devem ser válidos.
model Transaction {
id Int @id @default(autoincrement())
userId Int
subTotal Decimal @default(0) @db.Decimal(10, 2)
total Decimal @default(0) @db.Decimal(10, 2)
status String
}
Se qualquer campo obrigatório estiver ausente ou contiver dados inválidos, o banco de dados rejeita a transação, mantendo a consistência.
3. Isolamento (Isolation)
O isolamento garante que transações concorrentes não interfiram umas com as outras. Cada transação é executada como se fosse a única operando no sistema.
Exemplo:
Se dois usuários iniciam transações simultaneamente, a propriedade de isolamento garante que os cálculos de saldo permaneçam precisos.
await this.prisma.$transaction([operation1, operation2]);
O PostgreSQL lida com diferentes níveis de isolamento (READ COMMITTED
, SERIALIZABLE
, etc.) para gerenciar operações concorrentes.
4. Durabilidade (Durability)
A durabilidade garante que, uma vez que uma transação é confirmada, ela permanece persistente, mesmo em caso de falha do sistema.
Exemplo:
Após registrar com sucesso uma transação financeira, os dados permanecem intactos e disponíveis, independentemente de falhas no servidor.
await this.prisma.transaction.create({
data: {
userId: userId,
subTotal: amount,
total: amount,
status: 'PROCESSED',
},
});
Uma vez confirmada, o PostgreSQL garante que a transação persista no disco.
Conclusão
As transações ACID são essenciais para garantir a confiabilidade e integridade das operações financeiras em aplicações fintech. Compreender e implementar corretamente as propriedades de Atomicidade, Consistência, Isolamento e Durabilidade é fundamental para construir serviços financeiros seguros e escaláveis.
Top comments (0)