<h2>Configuração Inicial: PostgreSQL vs MySQL em Node.js</h2>
<p>Trabalhar com bancos de dados relacionais em Node.js exige escolher a biblioteca correta. PostgreSQL utiliza a biblioteca <strong>pg</strong>, enquanto MySQL usa <strong>mysql2</strong>. 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.</p>
<p>Para começar, instale as dependências necessárias:</p>
<pre><code class="language-bash">npm install pg mysql2</code></pre>
<p>Se optar por usar <strong>promises</strong> ao invés de callbacks (recomendado), use <code>mysql2/promise</code>. Ambas as bibliotecas suportam connection pooling nativo, essencial para aplicações em produção.</p>
<h2>Conexão e Query Básica</h2>
<h3>Configurando PostgreSQL com pg</h3>
<p>A biblioteca <strong>pg</strong> trabalha com a sintaxe padrão do PostgreSQL. Crie um arquivo <code>db.js</code> para centralizar a configuração:</p>
<pre><code class="language-javascript">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;</code></pre>
<p>Para executar queries com segurança (prevenindo SQL injection), sempre use parametrizadas:</p>
<pre><code class="language-javascript">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);
}
);</code></pre>
<h3>Configurando MySQL com mysql2</h3>
<p>O MySQL funciona de forma similar, mas com sintaxe ligeiramente diferente. Use <code>mysql2/promise</code> para melhor controle:</p>
<pre><code class="language-javascript">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;</code></pre>
<p>Queries com MySQL2 usando promises:</p>
<pre><code class="language-javascript">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));</code></pre>
<h2>CRUD Completo com Async/Await</h2>
<h3>Implementação com PostgreSQL</h3>
<p>Aqui está um exemplo completo de operações CRUD:</p>
<pre><code class="language-javascript">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 };</code></pre>
<h3>Implementação com MySQL</h3>
<p>O padrão é idêntico, mudando apenas a sintaxe dos placeholders (? em vez de $1):</p>
<pre><code class="language-javascript">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 };</code></pre>
<h2>Boas Práticas e Performance</h2>
<p><strong>Connection Pooling</strong> é 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.</p>
<p>Use <strong>prepared statements</strong> sempre para prevenir SQL injection. Em PostgreSQL, use <code>$1, $2</code>, em MySQL use <code>?</code>. Evite concatenar strings em queries.</p>
<p>Para aplicações médias e grandes, considere usar <strong>ORMs</strong> 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.</p>
<p>Um exemplo de middleware Express com tratamento robusto:</p>
<pre><code class="language-javascript">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...'));</code></pre>
<h2>Conclusão</h2>
<p>Os pontos principais para dominar bancos de dados em Node.js são: <strong>(1)</strong> escolha a biblioteca correta conforme seu banco (pg para PostgreSQL, mysql2 para MySQL), <strong>(2)</strong> sempre use async/await com pools de conexão para melhor performance e segurança, e <strong>(3)</strong> 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.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.npmjs.com/package/pg" target="_blank" rel="noopener noreferrer">PostgreSQL pg - npm</a></li>
<li><a href="https://github.com/sidorares/node-mysql2" target="_blank" rel="noopener noreferrer">MySQL2 Documentation</a></li>
<li><a href="https://github.com/goldbergyoni/nodebestpractices#5-database-best-practices" target="_blank" rel="noopener noreferrer">Node.js Best Practices - Database Connections</a></li>
<li><a href="https://owasp.org/www-community/attacks/SQL_Injection" target="_blank" rel="noopener noreferrer">SQL Injection Prevention - OWASP</a></li>
<li><a href="https://sequelize.org/" target="_blank" rel="noopener noreferrer">Sequelize ORM Documentation</a></li>
</ul>