🏗️ CAPÍTULO 02: FUNDAMENTOS DE SGBDS E SISTEMAS DE ARQUIVOS
🎯 Objetivos de Aprendizagem
Ao final deste capítulo (estimativa: 2 horas de estudo autoguiado), você será capaz de:
- 🔹 Analisar os 6 problemas clássicos da Era Pré-SGBD (Redundância, Inconsistência, Isolamento, Integridade, Atomicidade e Concorrência).
- 🔹 Avaliar por que planilhas eletrônicas (Excel) são inadequadas para armazenamento de dados transacionais corporativos.
- 🔹 Compreender os 4 pilares do modelo relacional: Autodescrição, Abstração, Múltiplas Visões e Concorrência.
- 🔹 Implementar tabelas protegidas por restrições de integridade no SQLite e PostgreSQL.
Seja bem-vindo(a) à base da pirâmide do conhecimento em tecnologia. Nesta unidade, desconstruiremos a forma como as aplicações modernas armazenam e processam seu maior ativo: o Dado. 🛡️🧩
🏢 O Cenário Prático (Seu Desafio)
Imagine que você assumiu como Arquiteto de Banco de Dados na TecProExpress. A empresa atualizou o sistema de rastreamento de entregas, mas o setor de atendimento ainda salva os contatos dos clientes no Excel.
"Seu desafio é demonstrar para a diretoria, de forma técnica e prática, por que manter dados de clientes em planilhas gera inconsistência e por que a TecProExpress deve centralizar tudo no novo SGBD."
🧠 Fundamentos: A Teoria Traduzida
0. Sistemas de Arquivos: A Era Pré-SGBD
Antes de existir um SGBD, aplicações corporativas guardavam dados diretamente em arquivos no disco (um .dat ou .txt por programa, lido e escrito linha a linha pelo próprio código da aplicação). Esse modelo é chamado de Sistema de Processamento de Arquivos (File Processing System), e é o motivo histórico pelo qual o SGBD foi inventado.
flowchart LR
subgraph "Era Pré-SGBD (Arquivos)"
AppA["App de Vendas"] --> ArqA[("clientes_vendas.dat")]
AppB["App de Cobrança"] --> ArqB[("clientes_cobranca.dat")]
end
Cada aplicação mantinha sua própria cópia dos dados, sem nenhuma camada central de controle. Isso gerava seis problemas clássicos, catalogados na literatura de Banco de Dados:
| Problema | O que acontecia na prática |
|---|---|
| Redundância e Inconsistência | O mesmo cliente cadastrado em clientes_vendas.dat e em clientes_cobranca.dat; se o telefone mudasse, alguém tinha que lembrar de atualizar os dois arquivos — e quase sempre esquecia um. |
| Dificuldade de Acesso | Para responder "quais clientes de SP compraram no último mês?", um programador precisava escrever um programa novo, específico, lendo o arquivo inteiro linha a linha. |
| Isolamento de Dados | Os dados ficavam espalhados em formatos e arquivos diferentes, dificultando escrever um programa que precisasse combinar informações de mais de um arquivo. |
| Problemas de Integridade | Regras de negócio (ex.: "saldo não pode ser negativo") ficavam soterradas dentro do código de cada aplicação, em vez de centralizadas — e cada app podia implementá-las (ou esquecê-las) de um jeito. |
| Problemas de Atomicidade | Uma queda de energia no meio de uma transferência bancária podia debitar de uma conta sem creditar na outra, sem nenhum mecanismo de recuperação. |
| Anomalias de Acesso Concorrente | Dois funcionários editando o mesmo arquivo ao mesmo tempo podiam sobrescrever a alteração um do outro, sem aviso. |
| Problemas de Segurança | Controlar quem podia ler ou alterar cada arquivo exigia lógica de permissão no sistema operacional, arquivo por arquivo — não havia um controle de acesso granular por dado. |
💡 A Virada de Chave: O SGBD nasceu exatamente para resolver esses seis problemas de uma vez só, através de uma camada única de software entre a aplicação e o disco — é o que vamos explorar no restante deste capítulo.
1. O Ciclo de Vida da Informação
Na engenharia de software de alta performance, trabalhamos com ativos que seguem um fluxo de valor:
flowchart TD
D["📄 DADO<br/>Fato Bruto"] --> P{"⚙️ SGBD<br/>Processamento"}
P --> I["📊 INFORMAÇÃO<br/>Conhecimento"]
I --> V["💰 VALOR<br/>Decisão Estratégica"]
🔍 Detalhamento do Fluxo:
- DADO: Um fato isolado, por exemplo, o texto
"TecProExpress". Sozinho, ele é mudo. - INFORMAÇÃO: O dado contextualizado.
"TecProExpress é o nosso cliente VIP de transporte". - BANCO DE DADOS (DB): Uma coleção de dados logicamente relacionados.
- SGBD (Sistema Gerenciador): O motor de execução (ex: MySQL 8.4) que processa esses dados em alta velocidade.
2. Por que não usar planilhas?
| Característica | Planilhas (Excel) 📁 | SGBD Relacional (MySQL/Postgres) 🛡️ |
|---|---|---|
| Redundância | Alta (nomes repetidos) | Minimizada e controlada |
| Integridade | Depende de quem digita | Automática com Constraints (CHECK, PK) |
| Acesso Simultâneo | Bloqueia o arquivo para outros | Permite milhares de transações ao mesmo tempo |
📖 Exemplo Guiado: Protegendo os Dados (DDL -> DML)
A principal vantagem do SGBD é a Integridade. Veja como o SGBD impede erros que uma planilha permitiria. Lembre-se do fluxo obrigatório: primeiro desenhamos a tabela (DDL), depois inserimos o dado (DML).
🛠️ Código do Exemplo
-- PASSO 1: DDL (Criação da Estrutura com Regras)
CREATE TABLE cliente_vip (
id INT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
limite_credito DECIMAL(10,2) CHECK (limite_credito >= 0)
);
-- PASSO 2: DML (Inserção Válida)
INSERT INTO cliente_vip (id, nome, limite_credito) VALUES (1, 'TecProExpress', 5000.00);
-- PASSO 3: Tentativa de Erro (O SGBD bloqueia!)
-- INSERT INTO cliente_vip (id, nome, limite_credito) VALUES (2, 'Transportadora B', -100.00);
🔍 Detalhamento do Código:
NOT NULL: Regra que impede que um cliente seja salvo sem nome. (No Excel, isso passaria).CHECK (limite_credito >= 0): Regra matemática. O SGBD recusa qualquer limite de crédito negativo. O Passo 3 falharia de propósito para proteger os dados.
🛠️ Prática Obrigatória: Abstração de Dados
Cenário: O catálogo interno da TecProExpress. Um SGBD guarda a "receita" do banco (Metadados) em um Catálogo interno. Isso permite que diferentes perfis vejam o mesmo dado de formas diferentes.
- Crie uma visão (View) simulando o painel de um Gerente, que quer ver os dados de faturamento.
- Não se preocupe se errar a sintaxe avançada, foque na estrutura.
🚀 Script de Seed (Gabarito de Visão)
-- PASSO 1: DDL (Criar Tabela Mestre)
CREATE TABLE faturamento (
id INT PRIMARY KEY,
filial VARCHAR(50),
lucro_total DECIMAL(15,2)
);
-- PASSO 2: DML (Popular)
INSERT INTO faturamento VALUES (101, 'São Paulo', 250000.00);
INSERT INTO faturamento VALUES (102, 'Rio de Janeiro', 180000.00);
-- PASSO 3: DDL (Criar a VIEW - Visão do Usuário)
CREATE VIEW relatorio_gerente AS
SELECT filial, lucro_total FROM faturamento WHERE lucro_total > 200000;
🔍 Detalhamento do Seed:
- CREATE VIEW: Cria um "atalho" ou "lente virtual" que filtra os dados originais. O Gerente só verá a filial de São Paulo.
💻 Ponte Prática: Do SQL Manual ao SQLAlchemy 2.0 ORM
Como o SQLAlchemy 2.0 traduz os conceitos de Integridade, Constraints e Catálogo de Metadados para o código Python?
🔴 1. A Abordagem Manual (Gravação em Arquivos / CSV sem Validação)
Sem as travas do SGBD, qualquer dado inválido é gravado no disco sem aviso:
# ❌ ABORDAGEM SEM SGBD: Dicionários ou CSV aceitam dados absurdos
def salvar_cliente_csv(nome, limite):
with open("clientes.csv", "a") as f:
f.write(f"{nome},{limite}\n")
salvar_cliente_csv(nome="", limite=-5000.0) # ⚠️ Aceito sem nenhum erro!
🟢 2. A Abordagem com SQLAlchemy 2.0 (CheckConstraint e Integridade de Domínio)
Com o SQLAlchemy 2.0, definimos CheckConstraint e nullable=False diretamente na declaração da classe. Se alguém tentar gravar um limite negativo, o próprio motor do banco rejeita:
# ✅ ABORDAGEM COM SQLALCHEMY 2.0: Restrições de Integridade Relacional
from sqlalchemy import create_engine, String, Float, CheckConstraint, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.exc import IntegrityError
class Base(DeclarativeBase):
pass
class ClienteVipModel(Base):
__tablename__ = "clientes_vip"
__table_args__ = (
CheckConstraint("limite_credito >= 0.0", name="chk_limite_positivo"),
)
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
nome: Mapped[str] = mapped_column(String(100), nullable=False)
limite_credito: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
def __repr__(self) -> str:
return f"ClienteVip(id={self.id}, nome='{self.nome}', limite=R$ {self.limite_credito:.2f})"
🛠️ Mini-Projeto 02 (BD): Validador de Integridade e Constraints
Objetivo: Criar uma tabela protegida com CheckConstraint e testar como o banco bloqueia transações que violam regras de integridade de domínio.
📋 Pré-requisitos e Instalação
No terminal do seu ambiente virtual (PowerShell ou Bash), instale a biblioteca necessária:
pip install sqlalchemy
💻 Código Completo e Autocontido (miniprojeto_02_integridade.py)
Crie o arquivo miniprojeto_02_integridade.py e insira o código abaixo integralmente:
"""
Mini-Projeto 02: Validador de Integridade e Constraints
Curso: GTI - Banco de Dados Relacionais e Engenharia de Software
Stack: Python 3.11+ | SQLAlchemy 2.0 | SQLite
"""
import os
from sqlalchemy import create_engine, String, Float, CheckConstraint, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.exc import IntegrityError
# 1. Definição Declarativa com Restrições de Integridade (Constraints)
class Base(DeclarativeBase):
pass
class ClienteVipModel(Base):
__tablename__ = "clientes_vip"
__table_args__ = (
CheckConstraint("limite_credito >= 0.0", name="chk_limite_positivo"),
)
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
nome: Mapped[str] = mapped_column(String(100), nullable=False)
limite_credito: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
def __repr__(self) -> str:
return f"ClienteVip(id={self.id}, nome='{self.nome}', limite=R$ {self.limite_credito:.2f})"
# 2. Ponto de Entrada Executável
if __name__ == "__main__":
DB_FILE = "tecpro_integridade.db"
# Reset preventivo para garantir reprodutibilidade em execuções sucessivas
if os.path.exists(DB_FILE):
os.remove(DB_FILE)
engine = create_engine(f"sqlite:///{DB_FILE}", echo=False)
Base.metadata.create_all(bind=engine)
print("🛡️ TESTE DE INTEGRIDADE RELACIONAL COM SQLALCHEMY 2.0")
print("=" * 60)
# 1. Inserção Válida:
with Session(engine) as session:
cliente_valido = ClienteVipModel(nome="TecProExpress Matriz", limite_credito=15000.0)
session.add(cliente_valido)
session.commit()
print(f"✅ Inserção Válida Concluída: {cliente_valido}")
# 2. Tentativa de Inserção Inválida (Limite Negativo):
with Session(engine) as session:
try:
print("\n⚠️ Tentando inserir cliente com limite negativo (-500.00)...")
cliente_invalido = ClienteVipModel(nome="Cliente Inadimplente", limite_credito=-500.0)
session.add(cliente_invalido)
session.commit()
except IntegrityError:
session.rollback()
print("🛡️ BLOQUEIO DO SGBD: Transação revertida com sucesso (IntegrityError)!")
print(" Regra 'chk_limite_positivo' protegeu a consistência dos dados.")
# 3. Consulta final confirmando que apenas o registro válido existe:
with Session(engine) as session:
stmt = select(ClienteVipModel)
registros = session.scalars(stmt).all()
print(f"\n📊 Total de registros íntegros no banco: {len(registros)}")
🚀 Como Executar
Execute o script no terminal:
python miniprojeto_02_integridade.py
🖥️ Saída Esperada no Console
🛡️ TESTE DE INTEGRIDADE RELACIONAL COM SQLALCHEMY 2.0
============================================================
✅ Inserção Válida Concluída: ClienteVip(id=1, nome='TecProExpress Matriz', limite=R$ 15000.00)
⚠️ Tentando inserir cliente com limite negativo (-500.00)...
🛡️ BLOQUEIO DO SGBD: Transação revertida com sucesso (IntegrityError)!
Regra 'chk_limite_positivo' protegeu a consistência dos dados.
📊 Total de registros íntegros no banco: 1
💡 Checkpoint de Lógica
Reflexão Profissional: Qual a diferença entre um DB (Database) e um DBMS (Sistema Gerenciador de Banco de Dados)? O DB é o arquivo salvo no disco rígido. O DBMS é o software (MySQL, Postgres, SQLite) que você usa para conversar com esse arquivo e garantir a segurança dele de forma simultânea. 🧠🛡️
🧪 Quiz de Fixação e Autoavaliação — Capítulo 02
🧪 Quiz de Fixação e Autoavaliação — Capítulo 02
1. Qual problema clássico dos sistemas antigos baseados em arquivos ocorre quando o mesmo telefone de cliente é atualizado em um arquivo, mas esquecido em outro?
- A) Problema de Conectividade de Rede
- B) Redundância e Inconsistência de Dados
- C) Falha de Hardware
- D) Overflow de Memória
💡 Ver Resposta e Justificativa
Resposta Correta: B
Justificativa: Sem um banco centralizado, dados duplicados em múltiplos arquivos ficam desalinhados quando ocorrem atualizações parciais, gerando inconsistência grave.
2. Por que uma planilha Excel não deve ser usada como banco de dados transacional de um sistema de vendas com 50 atendentes simultâneos?
- A) Porque o Excel não aceita números decimais.
- B) Porque planilhas bloqueiam o arquivo inteiro para escrita concorrente, não oferecem garantias transacionais ACID reais e não garantem integridade referencial automática.
- C) Porque planilhas só funcionam no Windows.
- D) Porque o Excel não permite criar colunas de texto.
💡 Ver Resposta e Justificativa
Resposta Correta: B
Justificativa: Planilhas não possuem controle transacional multi-usuário (MVCC), bloqueando o arquivo ou sobrescrevendo alterações de outros usuários sem aviso.
3. O que significa a característica de 'Autodescrição' (Auto-cataloga) de um banco de dados relacional?
- A) O banco escreve o código Python sozinho.
-
B) O banco de dados armazena não apenas os dados do usuário, mas também os seus próprios metadados (definição de tabelas, tipos, constraints e índices) em um catálogo interno do sistema (ex:
information_schema). - C) O banco apaga registros antigos automaticamente.
- D) O banco avisa quando a memória RAM está cheia.
💡 Ver Resposta e Justificativa
Resposta Correta: B
Justificativa: SGBDs são autodescritivos: a estrutura do schema é mantida em tabelas de catálogo do próprio SGBD, permitindo que ORMs e ferramentas inspecionem os dados.
Coloque este conhecimento em prática agora mesmo executando o roteiro autoguiado:
👉 ATIVIDADE 01: SETUP DO AMBIENTE