📚 Pré-requisitos Teóricos: este projeto aplica conceitos ensinados em Módulo 08: Bancos de Dados SQL e NoSQL. Recomendado revisar antes de começar.
v1.0 — Normalização Formal (1FN a 3FN), Bloqueio Pessimista e Controle de Crediário
Trilha de Engenharia de Dados & Bancos de Dados — Projeto 5 de 10
- v1: Modelagem Relacional 3FN · PostgreSQL 16
- v2: Modelagem NoSQL · MongoDB 7.0
- v3: Estratégias de Cache · Redis 7.2
- v4: DBA Enterprise · Particionamento & RLS · PostgreSQL 16
- ➡️ v5 (este): Modelagem Visual EER & Stored Procedures · MySQL 8.0
- v6: Séries Temporais IoT · Apache Cassandra 5.0
- v7: Prontuário Objeto-Relacional & JSONB · PostgreSQL 16
- v8: Rastreamento de Fraudes em Grafos · Neo4j 5.x
- v9: Data Warehouse & Consultas OLAP · PostgreSQL 16
- v10: Persistência Poliglota Integrada · Postgres + Mongo + Redis
🎓 Nível Profissional Simulado: Desenvolvedor Pleno / Especialista SQL. No comércio varejista de bairro com crediário próprio (caderneta/fiado), a gestão de débitos e amortizações precisa de garantia transacional absoluta com bloqueio de concorrência (
SELECT ... FOR UPDATE), evitando amortizações duplicadas ou saldos negativos.
Modelar um esquema visual EER para controle de vendas a prazo e amortização de fiado no MySQL 8.0, aplicando decomposição formal até a Terceira Forma Normal (3FN) e construindo uma Stored Procedure Transacional (sp_registrar_pagamento_fiado) com controle explícito de START TRANSACTION, COMMIT, ROLLBACK e bloqueio de linha.
erDiagram
CLIENTES ||--o{ VENDAS : "compra (1:N)"
CLIENTES ||--o{ RECIBOS_PAGAMENTO : "amortiza (1:N)"
VENDAS ||--|{ ITENS_VENDA : "possui (1:N)"
PRODUTOS ||--o{ ITENS_VENDA : "vendido_em (1:N)"
CLIENTES {
int id PK
string nome
string cpf UK
decimal saldo_devedor "CHECK >= 0"
decimal limite_credito
}
PRODUTOS {
int id PK
string codigo_barras UK
string nome
decimal preco_venda "CHECK > 0"
int estoque_atual "CHECK >= 0"
}
VENDAS {
int id PK
int cliente_id FK
datetime data_venda
enum forma_pagamento "A_VISTA|CREDIARIO_FIADO|CARTAO"
decimal valor_total
}
RECIBOS_PAGAMENTO {
int id PK
int cliente_id FK
decimal valor_pago "CHECK > 0"
datetime data_pagamento
}
“No nosso mercado, muitos clientes compram fiado e pagam aos poucos todo sábado. Tivemos casos em que dois caixas registraram o pagamento ao mesmo tempo e o saldo do cliente ficou negativado, ou o sistema caiu no meio do processo e o dinheiro sumiu do caixa sem dar baixa na conta do cliente. Precisamos de uma rotina blindada que bloqueie a conta durante o pagamento e garanta que o recibo só seja emitido se o débito for abatido com sucesso.”
| ID | Tipo | Descrição | Origem no Briefing |
|---|---|---|---|
| RF01 | Funcional | Permitir amortização parcial ou total do saldo devedor do cliente via Stored Procedure. | “pagam aos poucos todo sábado” |
| RF02 | Funcional | Impedir pagamentos com valor superior ao saldo devedor atual (valor_pago <= saldo_devedor). |
“saldo do cliente ficou negativado” |
| RF03 | Funcional | Gerar recibo histórico atômico com data e valor no mesmo momento do abatimento. | “recibo só emitido se abatido” |
| RNF01 | Não-Funcional | Bloqueio pessimista de linha (FOR UPDATE) para evitar concorrência entre caixas. |
Atomicidade de Caixa |
| RNF02 | Não-Funcional | Engine transacional InnoDB com rollback automático em caso de falha de hardware/rede. | Confiabilidade ACID |
| ID | User Story | Prioridade |
|---|---|---|
| US01 | Como operador de caixa, quero amortizar o fiado do cliente chamando uma Stored Procedure segura. | Alta |
| US02 | Como cliente, quero receber o recibo comprovando o valor pago e o novo saldo devedor. | Alta |
| US03 | Como gerente, quero que tentativas de pagamento inválidas disparem rollback sem afetar os dados. | Alta |
# Branch da funcionalidade
git checkout -b feature/US01-mysql-stored-procedure
# Subir o MySQL isolado via Docker
docker-compose up -d
# Conectar via MySQL Client
docker exec -it db_mysql_varejo mysql -u lojista -plojistapassword varejo_db
sql/02_procedure_pagamento.sql)DELIMITER $$
CREATE PROCEDURE sp_registrar_pagamento_fiado(
IN p_cliente_id INT,
IN p_valor_pago DECIMAL(10,2),
OUT p_status_mensagem VARCHAR(100)
)
BEGIN
DECLARE v_saldo_devedor DECIMAL(10,2);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SET p_status_mensagem = 'ERRO: Falha ao processar a transação.';
END;
START TRANSACTION;
SELECT saldo_devedor INTO v_saldo_devedor
FROM clientes
WHERE id = p_cliente_id FOR UPDATE;
IF v_saldo_devedor IS NULL THEN
SET p_status_mensagem = 'ERRO: Cliente inexistente.';
ROLLBACK;
ELSEIF p_valor_pago > v_saldo_devedor THEN
SET p_status_mensagem = 'ERRO: Pagamento maior que o débito.';
ROLLBACK;
ELSE
UPDATE clientes
SET saldo_devedor = saldo_devedor - p_valor_pago
WHERE id = p_cliente_id;
INSERT INTO recibos_pagamento (cliente_id, valor_pago, data_pagamento)
VALUES (p_cliente_id, p_valor_pago, NOW());
SET p_status_mensagem = 'SUCESSO: Pagamento amortizado.';
COMMIT;
END IF;
END$$
DELIMITER ;
FOR UPDATE para garantir consistência no crediário.No seu editor/IDE, abra a pasta deste projeto (File > Open Folder) ou navegue via terminal:
cd db_sql_05_mysql_eer_procedures
docker-compose up -d
# Executar a suíte de testes automatizados:
python -m unittest tests/test_mysql_procedures.py
[!TIP] Dica para execução a partir da raiz do repositório: Se você abriu o repositório completo no VS Code, basta navegar até a pasta antes de executar:
cd catalogo_projetos/db_sql_05_mysql_eer_procedures
-- 1. Executar a Stored Procedure para amortizar R$ 150.00
CALL sp_registrar_pagamento_fiado(1, 150.00, @msg);
SELECT @msg AS resultado_operacao;
-- 2. Validar que o saldo devedor baixou para R$ 200.00
SELECT id, nome, saldo_devedor FROM clientes WHERE id = 1;
SELECT * FROM recibos_pagamento WHERE cliente_id = 1;
A arquitetura abaixo demonstra o fluxo de persistência, otimização e isolamento dos componentes na subpasta sql/:
flowchart TD
subgraph DDL["Modelagem & Schema (DDL)"]
S1["Tabelas / Coleções"] --> S2["Constraints & Índices"]
end
subgraph DML["Regras & Automação (DML / PL)"]
R1["Triggers / Aggregations"] --> R2["Procedimentos Transacionais"]
end
subgraph Perf["Otimização & Armazenamento"]
P1["Planos EXPLAIN / Partições"] --> P2["Garantia de ACID / TTL"]
end
subgraph Homolog["Homologação & Qualidade"]
Q1["Docker Compose & Scripts"] --> Q2["Checkpoints CP-01..05 PASS"]
end
DDL --> DML
DML --> Perf
Perf --> Homolog
style DDL fill:#e3f2fd,stroke:#1976d2,stroke-width:1.5px
style DML fill:#fffde7,stroke:#fbc02d,stroke-width:1.5px
style Perf fill:#e8f5e9,stroke:#388e3c,stroke-width:1.5px
style Homolog fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1.5px
| ID | Persona | História de Usuário | Critério de Aceite | Prioridade |
|---|---|---|---|---|
| US-01 | Arquiteto de Dados | Desejo modelagem EER para gestão de estoque e vendas de varejo | Diagrama visual com herança, subtipos e cardinalidades estritas no MySQL | Alta |
| US-02 | Desenvolvedor Backend | Desejo Stored Procedure para processamento de checkout com controle transacional | START TRANSACTION, COMMIT e ROLLBACK em handlers de SQLEXCEPTION | Alta |
| US-03 | DBA MySQL | Desejo triggers de auditoria registrando histórico de alterações de preços | Tabela de log populada automaticamente em eventos BEFORE/AFTER UPDATE | Alta |
| US-04 | Operador Financeiro | Desejo funções determinísticas (UDF) para cálculo de descontos progressivos | Function MySQL reutilizável em consultas SELECT e relatórios | Média |
| US-05 | Auditor de Sistemas | Desejo testes comprovando que falhas no meio do checkout não deixam dados órfãos | Bateria de testes simulando erros de concorrência e rollback automático | Média |
| ID | Descrição do Requisito | Criticidade |
|---|---|---|
| RF-01 | Modelo relacional EER completo com chaves primárias e estrangeiras | Alta |
| RF-02 | Stored Procedures de checkout com tratamento de exceções (DECLARE HANDLER) | Alta |
| RF-03 | Triggers de auditoria e versionamento de dados sensíveis | Alta |
| RF-04 | Funções customizadas para cálculo de impostos e tarifas no banco | Média |
| RF-05 | Scripts SQL organizados e suíte de testes de estresse transacional | Média |
| ID | Especificação Arquitetural | Criticidade |
|---|---|---|
| RNF-01 | Isolamento transacional REPEATABLE READ nativo do motor InnoDB | Alta |
| RNF-02 | Bloqueios pessimistas (SELECT … FOR UPDATE) prevenindo venda sem estoque | Alta |
| RNF-03 | Compatibilidade total com MySQL 8.0+ | Média |
| RNF-04 | Execução reprodutível via Docker Compose | Média |
| RNF-05 | Estruturação dos artefatos na pasta sql/ | Alta |
| User Story | Requisito Funcional | Requisito Não-Funcional | Módulo / Artefato de Código | Status de Homologação |
|---|---|---|---|---|
| US-01 | RF-01 |
RNF-01, RNF-03 |
sql/01_eer_schema.sql |
Testado |
| US-02 | RF-02 |
RNF-01, RNF-02 |
sql/02_procedures.sql |
Testado |
| US-03 | RF-03 |
RNF-01, RNF-04 |
sql/03_triggers.sql |
Testado |
| US-04 | RF-04 |
RNF-02, RNF-03 |
sql/04_functions.sql |
Testado |
| US-05 | RF-05 |
RNF-01, RNF-05 |
tests/test_procedures.py |
Testado |
| Checkpoint | Escopo da Validação | Artefato Verificado | Status |
|---|---|---|---|
| CP-01 | Subida Conteinerizada do Ambiente | docker-compose.yml |
PASS ✅ |
| CP-02 | Criação de Estrutura & Schemas | sql/ |
PASS ✅ |
| CP-03 | Automação Transacional & Regras | Triggers / Queries |
PASS ✅ |
| CP-04 | Otimização de Performance & Índices | Indexes / Tuning |
PASS ✅ |
| CP-05 | Homologação com Suíte de Testes | tests/ |
PASS ✅ |