JavaScript

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

7 min de leitura

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

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:

<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(&#039;pg&#039;);

const pool = new Pool({

user: &#039;seu_usuario&#039;,

password: &#039;sua_senha&#039;,

host: &#039;localhost&#039;,

port: 5432,

database: &#039;sua_database&#039;

});

// Testando a conexão

pool.query(&#039;SELECT NOW()&#039;, (err, res) =&gt; {

if (err) console.error(&#039;Erro:&#039;, err);

else console.log(&#039;Conectado:&#039;, 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(&#039;./db&#039;);

pool.query(

&#039;SELECT * FROM usuarios WHERE id = $1&#039;,

[1],

(err, res) =&gt; {

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(&#039;mysql2/promise&#039;);

const pool = mysql.createPool({

host: &#039;localhost&#039;,

user: &#039;seu_usuario&#039;,

password: &#039;sua_senha&#039;,

database: &#039;sua_database&#039;,

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(&#039;./db&#039;);

async function buscarUsuario(id) {

const connection = await pool.getConnection();

try {

const [rows] = await connection.query(

&#039;SELECT * FROM usuarios WHERE id = ?&#039;,

[id]

);

return rows;

} finally {

connection.release();

}

}

buscarUsuario(1).then(user =&gt; 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(&#039;./db&#039;);

// CREATE

async function criarUsuario(nome, email) {

try {

const result = await pool.query(

&#039;INSERT INTO usuarios (nome, email) VALUES ($1, $2) RETURNING *&#039;,

[nome, email]

);

return result.rows[0];

} catch (erro) {

console.error(&#039;Erro ao criar:&#039;, erro);

}

}

// READ

async function obterUsuarios() {

try {

const result = await pool.query(&#039;SELECT * FROM usuarios&#039;);

return result.rows;

} catch (erro) {

console.error(&#039;Erro ao buscar:&#039;, erro);

}

}

// UPDATE

async function atualizarUsuario(id, nome, email) {

try {

const result = await pool.query(

&#039;UPDATE usuarios SET nome = $1, email = $2 WHERE id = $3 RETURNING *&#039;,

[nome, email, id]

);

return result.rows[0];

} catch (erro) {

console.error(&#039;Erro ao atualizar:&#039;, erro);

}

}

// DELETE

async function deletarUsuario(id) {

try {

await pool.query(&#039;DELETE FROM usuarios WHERE id = $1&#039;, [id]);

return { sucesso: true };

} catch (erro) {

console.error(&#039;Erro ao deletar:&#039;, 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(&#039;./db&#039;);

async function criarUsuario(nome, email) {

const connection = await pool.getConnection();

try {

const [result] = await connection.query(

&#039;INSERT INTO usuarios (nome, email) VALUES (?, ?)&#039;,

[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(&#039;SELECT * FROM usuarios&#039;);

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(&#039;express&#039;);

const { obterUsuarios, criarUsuario } = require(&#039;./usuario&#039;);

const app = express();

app.use(express.json());

app.get(&#039;/usuarios&#039;, async (req, res) =&gt; {

try {

const usuarios = await obterUsuarios();

res.json(usuarios);

} catch (erro) {

res.status(500).json({ erro: &#039;Falha ao buscar usuários&#039; });

}

});

app.post(&#039;/usuarios&#039;, async (req, res) =&gt; {

try {

const { nome, email } = req.body;

if (!nome || !email) {

return res.status(400).json({ erro: &#039;Nome e email obrigatórios&#039; });

}

const usuario = await criarUsuario(nome, email);

res.status(201).json(usuario);

} catch (erro) {

res.status(500).json({ erro: &#039;Falha ao criar usuário&#039; });

}

});

app.listen(3000, () =&gt; console.log(&#039;Servidor rodando...&#039;));</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>

Comentários

Mais em JavaScript

Formulários em JavaScript: Validação, Submissão e FormData: Do Básico ao Avançado
Formulários em JavaScript: Validação, Submissão e FormData: Do Básico ao Avançado

Validação de Formulários com JavaScript A validação de formulários é a primei...

Dominando Hooks em React: useState, useEffect, useRef e useCallback em Projetos Reais
Dominando Hooks em React: useState, useEffect, useRef e useCallback em Projetos Reais

useState: Gerenciando Estado em Componentes Funcionais O é o hook fundamental...

O que Todo Dev Deve Saber sobre Bundlers em JavaScript: Vite, Webpack e esbuild na Prática
O que Todo Dev Deve Saber sobre Bundlers em JavaScript: Vite, Webpack e esbuild na Prática

O que é um Bundler e Por que Precisamos Deles Um bundler é uma ferramenta que...