---
title: "Python e SQLite — 2025 | Python Brasil"
url: "https://python.dev.br/blog/python-e-banco-de-dados-sqlite/"
markdown_url: "https://python.dev.br/blog/python-e-banco-de-dados-sqlite.MD"
description: "Aprenda a usar banco de dados SQLite com Python. CRUD completo, consultas e boas práticas com exemplos. Confira!"
date: "2025-12-01"
author: "Equipe Python Brasil"
---

# Python e SQLite — 2025 | Python Brasil

Aprenda a usar banco de dados SQLite com Python. CRUD completo, consultas e boas práticas com exemplos. Confira!


SQLite é um banco de dados leve, embutido e que não requer um servidor separado para funcionar. Ele armazena todo o banco em um único arquivo, tornando-o perfeito para aplicações desktop, protótipos, projetos pequenos e médios, e até mesmo para testes de aplicações que em produção usarão bancos maiores como PostgreSQL ou MySQL.

O Python traz o módulo `sqlite3` na biblioteca padrão, o que significa que você pode começar a trabalhar com banco de dados sem instalar nada adicional. Neste artigo, vamos cobrir todas as operações fundamentais com exemplos práticos.

## Conectando ao banco de dados

A conexão com SQLite é simples. Se o arquivo não existir, ele será criado automaticamente:

```python
import sqlite3

# Conectando (cria o arquivo se não existir)
conexao = sqlite3.connect("minha_aplicacao.db")
cursor = conexao.cursor()

print("Conexão estabelecida com sucesso.")

# Sempre feche a conexão ao terminar
conexao.close()
```

A forma recomendada é usar o gerenciador de contexto, que garante o fechamento automático:

```python
import sqlite3

with sqlite3.connect("minha_aplicacao.db") as conexao:
    cursor = conexao.cursor()
    # Operações com o banco aqui
    print("Operações concluídas.")
# A conexão é fechada automaticamente
```

## Criando tabelas

Vamos criar um esquema para um sistema simples de gerenciamento de produtos:

```python
import sqlite3

def criar_tabelas(conexao):
    """Cria as tabelas do sistema."""
    cursor = conexao.cursor()

    cursor.execute("""
        CREATE TABLE IF NOT EXISTS categorias (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nome TEXT NOT NULL UNIQUE,
            descricao TEXT
        )
    """)

    cursor.execute("""
        CREATE TABLE IF NOT EXISTS produtos (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nome TEXT NOT NULL,
            preco REAL NOT NULL,
            estoque INTEGER DEFAULT 0,
            categoria_id INTEGER,
            data_cadastro TEXT DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY (categoria_id) REFERENCES categorias(id)
        )
    """)

    conexao.commit()
    print("Tabelas criadas com sucesso.")

with sqlite3.connect("loja.db") as conexao:
    criar_tabelas(conexao)
```

O `CREATE TABLE IF NOT EXISTS` evita erros caso as tabelas já existam. O `commit()` confirma as alterações no banco.

## Inserindo dados (Create)

Para inserir dados, use placeholders (`?`) para evitar injeção de SQL:

```python
import sqlite3

def inserir_categoria(conexao, nome, descricao):
    """Insere uma nova categoria."""
    cursor = conexao.cursor()
    try:
        cursor.execute(
            "INSERT INTO categorias (nome, descricao) VALUES (?, ?)",
            (nome, descricao)
        )
        conexao.commit()
        print(f"Categoria '{nome}' inserida com ID {cursor.lastrowid}")
        return cursor.lastrowid
    except sqlite3.IntegrityError:
        print(f"Categoria '{nome}' já existe.")
        return None

def inserir_produto(conexao, nome, preco, estoque, categoria_id):
    """Insere um novo produto."""
    cursor = conexao.cursor()
    cursor.execute(
        "INSERT INTO produtos (nome, preco, estoque, categoria_id) VALUES (?, ?, ?, ?)",
        (nome, preco, estoque, categoria_id)
    )
    conexao.commit()
    print(f"Produto '{nome}' inserido com ID {cursor.lastrowid}")
    return cursor.lastrowid

with sqlite3.connect("loja.db") as conexao:
    criar_tabelas(conexao)

    # Inserindo categorias
    cat_eletronicos = inserir_categoria(conexao, "Eletrônicos", "Produtos eletrônicos em geral")
    cat_acessorios = inserir_categoria(conexao, "Acessórios", "Acessórios para computador")

    # Inserindo produtos
    if cat_eletronicos:
        inserir_produto(conexao, "Notebook Dell", 4500.00, 10, cat_eletronicos)
        inserir_produto(conexao, "Monitor LG 27\"", 1599.00, 25, cat_eletronicos)

    if cat_acessorios:
        inserir_produto(conexao, "Mouse Logitech", 149.90, 100, cat_acessorios)
        inserir_produto(conexao, "Teclado Mecânico", 349.90, 50, cat_acessorios)
```

Nunca construa queries concatenando strings diretamente. Sempre use placeholders para prevenir ataques de injeção de SQL.

### Inserção em lote

Para inserir muitos registros de uma vez, use `executemany`:

```python
def inserir_produtos_lote(conexao, produtos):
    """Insere vários produtos de uma vez."""
    cursor = conexao.cursor()
    cursor.executemany(
        "INSERT INTO produtos (nome, preco, estoque, categoria_id) VALUES (?, ?, ?, ?)",
        produtos
    )
    conexao.commit()
    print(f"{cursor.rowcount} produtos inseridos.")

# Uso:
# lista_produtos = [
#     ("SSD 1TB", 399.90, 40, 1),
#     ("RAM 16GB", 289.90, 60, 1),
#     ("Webcam HD", 199.90, 35, 2),
# ]
# inserir_produtos_lote(conexao, lista_produtos)
```

## Consultando dados (Read)

As consultas retornam tuplas por padrão, mas podemos configurar para retornar dicionários:

```python
import sqlite3

def consultar_todos_produtos(conexao):
    """Retorna todos os produtos."""
    conexao.row_factory = sqlite3.Row
    cursor = conexao.cursor()
    cursor.execute("""
        SELECT p.id, p.nome, p.preco, p.estoque, c.nome as categoria
        FROM produtos p
        LEFT JOIN categorias c ON p.categoria_id = c.id
        ORDER BY p.nome
    """)
    return cursor.fetchall()

def buscar_produto_por_nome(conexao, termo):
    """Busca produtos pelo nome."""
    cursor = conexao.cursor()
    cursor.execute(
        "SELECT id, nome, preco, estoque FROM produtos WHERE nome LIKE ?",
        (f"%{termo}%",)
    )
    return cursor.fetchall()

def produtos_com_estoque_baixo(conexao, limite=10):
    """Retorna produtos com estoque abaixo do limite."""
    cursor = conexao.cursor()
    cursor.execute(
        "SELECT nome, estoque FROM produtos WHERE estoque < ? ORDER BY estoque",
        (limite,)
    )
    return cursor.fetchall()

with sqlite3.connect("loja.db") as conexao:
    criar_tabelas(conexao)

    print("Todos os produtos:")
    for produto in consultar_todos_produtos(conexao):
        print(f"  {produto['nome']} - R$ {produto['preco']:.2f} ({produto['estoque']} un.)")
```

O `sqlite3.Row` permite acessar colunas tanto por índice quanto por nome, tornando o código mais legível.

## Atualizando dados (Update)

```python
def atualizar_preco(conexao, produto_id, novo_preco):
    """Atualiza o preço de um produto."""
    cursor = conexao.cursor()
    cursor.execute(
        "UPDATE produtos SET preco = ? WHERE id = ?",
        (novo_preco, produto_id)
    )
    conexao.commit()
    if cursor.rowcount > 0:
        print(f"Preço do produto {produto_id} atualizado para R$ {novo_preco:.2f}")
    else:
        print(f"Produto {produto_id} não encontrado.")

def atualizar_estoque(conexao, produto_id, quantidade):
    """Adiciona ou remove quantidade do estoque."""
    cursor = conexao.cursor()
    cursor.execute(
        "UPDATE produtos SET estoque = estoque + ? WHERE id = ?",
        (quantidade, produto_id)
    )
    conexao.commit()
    print(f"Estoque do produto {produto_id} ajustado em {quantidade} unidades.")
```

## Removendo dados (Delete)

```python
def remover_produto(conexao, produto_id):
    """Remove um produto pelo ID."""
    cursor = conexao.cursor()
    cursor.execute("DELETE FROM produtos WHERE id = ?", (produto_id,))
    conexao.commit()
    if cursor.rowcount > 0:
        print(f"Produto {produto_id} removido.")
    else:
        print(f"Produto {produto_id} não encontrado.")
```

## Classe gerenciadora do banco

Para projetos maiores, encapsule as operações em uma classe:

```python
import sqlite3
from contextlib import contextmanager

class GerenciadorLoja:
    def __init__(self, caminho_db):
        self.caminho_db = caminho_db

    @contextmanager
    def conectar(self):
        conexao = sqlite3.connect(self.caminho_db)
        conexao.row_factory = sqlite3.Row
        try:
            yield conexao
            conexao.commit()
        except Exception as e:
            conexao.rollback()
            raise e
        finally:
            conexao.close()

    def listar_produtos(self):
        with self.conectar() as conn:
            cursor = conn.cursor()
            cursor.execute("SELECT * FROM produtos ORDER BY nome")
            return [dict(row) for row in cursor.fetchall()]

    def relatorio_estoque(self):
        with self.conectar() as conn:
            cursor = conn.cursor()
            cursor.execute("""
                SELECT c.nome as categoria,
                       COUNT(p.id) as total_produtos,
                       SUM(p.estoque) as total_estoque,
                       SUM(p.preco * p.estoque) as valor_total
                FROM produtos p
                JOIN categorias c ON p.categoria_id = c.id
                GROUP BY c.nome
            """)
            return [dict(row) for row in cursor.fetchall()]

# Uso:
# loja = GerenciadorLoja("loja.db")
# for produto in loja.listar_produtos():
#     print(produto)
```

## Boas práticas com SQLite em Python

- **Use placeholders**: nunca concatene valores diretamente na query SQL.
- **Use transações**: agrupe operações relacionadas em transações com `commit()` e `rollback()`.
- **Feche conexões**: use gerenciadores de contexto (`with`) para garantir o fechamento.
- **Indexe colunas frequentes**: crie índices em colunas usadas em WHERE e JOIN para melhorar a performance.
- **Use `row_factory`**: `sqlite3.Row` torna o código mais legível e menos propenso a erros.
- **Trate exceções**: capture `sqlite3.IntegrityError` e `sqlite3.OperationalError` em operações críticas.

## Conclusão

SQLite com Python é uma combinação poderosa para armazenamento de dados local. O módulo `sqlite3` fornece tudo o que você precisa para criar aplicações com persistência de dados de forma simples e eficiente. Desde protótipos rápidos até aplicações de tamanho moderado, o SQLite atende com excelência.

Como próximos passos, explore ORMs como SQLAlchemy para abstrair as queries SQL, aprenda sobre migrações de banco de dados e, quando suas aplicações crescerem, considere a transição para PostgreSQL ou MySQL, mantendo a mesma lógica de código.

Outras linguagens também têm excelente suporte a SQLite — <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Go com `database/sql`</a> oferece acesso concorrente eficiente, e <a href="https://kotlin.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'kotlin.dev.br' })">Kotlin com Room</a> é a escolha padrão para bancos locais em apps Android.
