Boas Práticas de Banco de Dados em Node.js: PostgreSQL com pg e MySQL com mysql2 para Times Ágeis Já leu

Configuração Inicial: PostgreSQL vs MySQL em Node.js Trabalhar com bancos de dados relacionais em Node.js exige escolher a biblioteca correta. PostgreSQL utiliza a biblioteca pg, enquanto MySQL usa mysql2. Ambas são excelentes, mas têm características distintas. O PostgreSQL é mais robusto para aplicações complexas, enquanto MySQL é mais leve e amplamente suportado em hospedagens compartilhadas. Para começar, instale as dependências necessárias: Se optar por usar promises ao invés de callbacks (recomendado), use . Ambas as bibliotecas suportam connection pooling nativo, essencial para aplicações em produção. Conexão e Query Básica Configurando PostgreSQL com pg A biblioteca pg trabalha com a sintaxe padrão do PostgreSQL. Crie um arquivo para centralizar a configuração: Para executar queries com segurança (prevenindo SQL injection), sempre use parametrizadas: Configurando MySQL com mysql2 O MySQL funciona de forma similar, mas com sintaxe ligeiramente diferente. Use para melhor controle: Queries com MySQL2 usando promises: CRUD Completo com Async/Await Implementação com PostgreSQL Aqui está um exemplo completo de operações CRUD:

Configuração Inicial: PostgreSQL vs MySQL em Node.js

Trabalhar com bancos de dados relacionais em Node.js exige escolher a biblioteca correta. PostgreSQL utiliza a biblioteca pg, enquanto MySQL usa mysql2. Ambas são excelentes, mas têm características distintas. O PostgreSQL é mais robusto para aplicações complexas, enquanto MySQL é mais leve e amplamente suportado em hospedagens compartilhadas.

Para começar, instale as dependências necessárias:

npm install pg mysql2

Se optar por usar promises ao invés de callbacks (recomendado), use mysql2/promise. Ambas as bibliotecas suportam connection pooling nativo, essencial para aplicações em produção.

Conexão e Query Básica

Configurando PostgreSQL com pg

A biblioteca pg trabalha com a sintaxe padrão do PostgreSQL. Crie um arquivo db.js para centralizar a configuração:

const { Pool } = require('pg');

const pool = new Pool({
  user: 'seu_usuario',
  password: 'sua_senha',
  host: 'localhost',
  port: 5432,
  database: 'sua_database'
});

// Testando a conexão
pool.query('SELECT NOW()', (err, res) => {
  if (err) console.error('Erro:', err);
  else console.log('Conectado:', res.rows);
});

module.exports = pool;

Para executar queries com segurança (prevenindo SQL injection), sempre use parametrizadas:

const pool = require('./db');

pool.query(
  'SELECT * FROM usuarios WHERE id = $1',
  [1],
  (err, res) => {
    if (err) console.error(err);
    else console.log(res.rows);
  }
);

Configurando MySQL com mysql2

O MySQL funciona de forma similar, mas com sintaxe ligeiramente diferente. Use mysql2/promise para melhor controle:

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'seu_usuario',
  password: 'sua_senha',
  database: 'sua_database',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

module.exports = pool;

Queries com MySQL2 usando promises:

const pool = require('./db');

async function buscarUsuario(id) {
  const connection = await pool.getConnection();
  try {
    const [rows] = await connection.query(
      'SELECT * FROM usuarios WHERE id = ?',
      [id]
    );
    return rows;
  } finally {
    connection.release();
  }
}

buscarUsuario(1).then(user => console.log(user));

CRUD Completo com Async/Await

Implementação com PostgreSQL

Aqui está um exemplo completo de operações CRUD:

const pool = require('./db');

// CREATE
async function criarUsuario(nome, email) {
  try {
    const result = await pool.query(
      'INSERT INTO usuarios (nome, email) VALUES ($1, $2) RETURNING *',
      [nome, email]
    );
    return result.rows[0];
  } catch (erro) {
    console.error('Erro ao criar:', erro);
  }
}

// READ
async function obterUsuarios() {
  try {
    const result = await pool.query('SELECT * FROM usuarios');
    return result.rows;
  } catch (erro) {
    console.error('Erro ao buscar:', erro);
  }
}

// UPDATE
async function atualizarUsuario(id, nome, email) {
  try {
    const result = await pool.query(
      'UPDATE usuarios SET nome = $1, email = $2 WHERE id = $3 RETURNING *',
      [nome, email, id]
    );
    return result.rows[0];
  } catch (erro) {
    console.error('Erro ao atualizar:', erro);
  }
}

// DELETE
async function deletarUsuario(id) {
  try {
    await pool.query('DELETE FROM usuarios WHERE id = $1', [id]);
    return { sucesso: true };
  } catch (erro) {
    console.error('Erro ao deletar:', erro);
  }
}

module.exports = { criarUsuario, obterUsuarios, atualizarUsuario, deletarUsuario };

Implementação com MySQL

O padrão é idêntico, mudando apenas a sintaxe dos placeholders (? em vez de $1):

const pool = require('./db');

async function criarUsuario(nome, email) {
  const connection = await pool.getConnection();
  try {
    const [result] = await connection.query(
      'INSERT INTO usuarios (nome, email) VALUES (?, ?)',
      [nome, email]
    );
    return { id: result.insertId, nome, email };
  } finally {
    connection.release();
  }
}

async function obterUsuarios() {
  const connection = await pool.getConnection();
  try {
    const [rows] = await connection.query('SELECT * FROM usuarios');
    return rows;
  } finally {
    connection.release();
  }
}

module.exports = { criarUsuario, obterUsuarios };

Boas Práticas e Performance

Connection Pooling é fundamental. Ambas as bibliotecas gerenciam pools nativamente, mas configure limites apropriados: tipicamente 5-20 conexões conforme a carga. Nunca crie uma nova conexão para cada query.

Use prepared statements sempre para prevenir SQL injection. Em PostgreSQL, use $1, $2, em MySQL use ?. Evite concatenar strings em queries.

Para aplicações médias e grandes, considere usar ORMs como Sequelize ou TypeORM, que abstraem diferenças entre bancos. No entanto, conhecer SQL raw é essencial para debugging e otimização. Sempre adicione tratamento de erros e considere implementar logging para monitorar queries em produção.

Um exemplo de middleware Express com tratamento robusto:

const express = require('express');
const { obterUsuarios, criarUsuario } = require('./usuario');

const app = express();
app.use(express.json());

app.get('/usuarios', async (req, res) => {
  try {
    const usuarios = await obterUsuarios();
    res.json(usuarios);
  } catch (erro) {
    res.status(500).json({ erro: 'Falha ao buscar usuários' });
  }
});

app.post('/usuarios', async (req, res) => {
  try {
    const { nome, email } = req.body;
    if (!nome || !email) {
      return res.status(400).json({ erro: 'Nome e email obrigatórios' });
    }
    const usuario = await criarUsuario(nome, email);
    res.status(201).json(usuario);
  } catch (erro) {
    res.status(500).json({ erro: 'Falha ao criar usuário' });
  }
});

app.listen(3000, () => console.log('Servidor rodando...'));

Conclusão

Os pontos principais para dominar bancos de dados em Node.js são: (1) escolha a biblioteca correta conforme seu banco (pg para PostgreSQL, mysql2 para MySQL), (2) sempre use async/await com pools de conexão para melhor performance e segurança, e (3) implemente tratamento de erros robusto e queries parametrizadas para evitar vulnerabilidades. Com essa base sólida, você está pronto para construir aplicações profissionais e escaláveis.

Referências


Artigos relacionados