MySQL With Backend (বেস্ট প্র্যাকটিস এবং আর্কিটেকচার)
আপনার ডেটাবেস যতই ফাস্ট হোক, যদি আপনার ব্যাকএন্ড কোড খারাপ হয়, তবে পুরো সিস্টেম স্লো হয়ে যাবে। যেমন—প্রতি রিকোয়েস্টে নতুন কানেকশন খোলা বা লুপের ভেতরে কুয়েরি চালানো।
এই অধ্যায়ে আমরা শিখব কীভাবে একজন আর্কিটেক্টের মতো ব্যাকএন্ড কোড লিখতে হয় যা ডেটাবেসের সাথে দক্ষতার সাথে কথা বলে।
২১.১ Connection Pool (সবচেয়ে গুরুত্বপূর্ণ)
ডেটাবেসের সাথে কানেকশন তৈরি করা (TCP Handshake, Authentication) একটি সময়সাপেক্ষ এবং ব্যয়বহুল প্রক্রিয়া। প্রতি রিকোয়েস্টে নতুন কানেকশন খুললে সার্ভার ক্র্যাশ করবে।
❌ ভুল পদ্ধতি (Junior Dev):
// প্রতি রিকোয়েস্টে কানেকশন তৈরি হচ্ছে
app.get('/users', async (req, res) => {
const conn = await mysql.createConnection({...}); // ⚠️ Dangerous
// query...
conn.end();
});
✅ সঠিক পদ্ধতি (Connection Pool):
পুল হলো আগে থেকে তৈরি করে রাখা কানেকশনের একটি বাফার। রিকোয়েস্ট আসলে পুল থেকে একটি কানেকশন ধার নেয়, কাজ শেষে ফেরত দেয়।
// db.js (Singleton Pattern)
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'app_user',
password: 'secure_password',
database: 'production_db',
waitForConnections: true,
connectionLimit: 10, // সার্ভারের ক্ষমতা অনুযায়ী সেট করুন
queueLimit: 0
});
module.exports = pool;
💡 Senior Tip: Serverless (যেমন AWS Lambda বা Vercel) এ গ্লোবাল ভেরিয়েবলে পুল রাখতে হয়, নাহলে প্রতি ফাংশন কলে নতুন পুল তৈরি হয়ে "Too many connections" এরর দেয়।
২১.২ Prepared Statements (SQL Injection এর যম)
কখনোই ইউজার ইনপুট সরাসরি কুয়েরিতে জোড়া দেবেন না।
❌ ভলনারেবল:
const email = req.body.email;
const query = "SELECT * FROM users WHERE email = '" + email + "'";
হ্যাকার ইনপুট: ' OR '1'='1
✅ সিকিউর (Prepared Statement):
const email = req.body.email;
const [rows] = await pool.execute(
"SELECT * FROM users WHERE email = ?",
[email] // ড্রাইভার অটোমেটিক এস্কেপ করবে
);
২১.৩ The N+1 Query Problem (পারফরম্যান্স কিলার)
ব্যাকএন্ড ডেভেলপারদের সবচেয়ে কমন ভুল।
❌ ভুল (N+1):
৫০ জন ইউজার আনলেন (১ কুয়েরি), তারপর লুপ চালিয়ে প্রত্যেকের প্রোফাইল আনলেন (৫০ কুয়েরি)। মোট ৫১ কুয়েরি!
const users = await User.findAll();
for (const user of users) {
user.profile = await Profile.findOne({
userId: user.id
}); // ⚠️ লুপের ভেতরে কুয়েরি
}
✅ সঠিক (Eager Loading / JOIN):
মাত্র ১ বা ২ কুয়েরিতে সব ডেটা আনুন।
// SQL JOIN
const query = `SELECT u.*, p.bio
FROM users u LEFT JOIN profiles p
ON u.id = p.user_id`;
// ORM (Prisma/Laravel)
const users = await User.findMany({
include: { profile: true }
});
২১.৪ Transaction & Deadlock Retry Logic
প্রোডাকশনে ডেডলক হবেই। কোড ক্র্যাশ না করিয়ে রি-ট্রাই করা স্মার্ট ইঞ্জিনিয়ারের কাজ।
const executeTransaction = async (logicFunction) => {
const conn = await pool.getConnection();
let attempt = 0;
while (attempt < 3) { // ৩ বার চেষ্টা করবে
try {
await conn.beginTransaction();
await logicFunction(conn); // আসল কাজ এখানে
await conn.commit();
return; // সফল হলে বের হয়ে যাবে
} catch (err) {
await conn.rollback();
// যদি ডেডলক হয় (Error 1213), তবেই রি-ট্রাই
if (err.errno === 1213 && attempt < 2) {
attempt++;
await new Promise(r => setTimeout(r, 100)); // ১০০ms অপেক্ষা
continue;
}
throw err; // অন্য এরর হলে থ্রো করবে
} finally {
conn.release(); // কানেকশন ফেরত দেওয়া বাধ্যতামূলক
}
}
};
২১.৫ Efficient Pagination (Keyset vs Offset)
❌ Offset Pagination (Slow for large data):
LIMIT 1000000, 20
প্রথম ১ মিলিয়ন রো স্ক্যান করে ফেলে দেয়।
✅ Keyset Pagination (Infinite Scroll):
SELECT * FROM products
WHERE id < ?
ORDER BY id DESC
LIMIT 20;
এটি সবসময় O(1) টাইমে কাজ করে।
২১.৬ Caching Strategy (Redis)
সব কুয়েরি ডেটাবেসে হিট করার দরকার নেই।
অ্যাপ রিকোয়েস্ট → Redis চেক
↓ (Cache Hit) ↓ (Cache Miss)
রিটার্ন MySQL → Redis → রিটার্ন
NestJS / Node.js Example:
async getProduct(id: number) {
const cacheKey = `product_${id}`;
const cached = await this.cacheManager.get(cacheKey);
if (cached) return cached;
const product = await this.repo.findOne(id);
await this.cacheManager.set(cacheKey, product, { ttl: 300 }); // ৫ মিনিট
return product;
}
২১.৭ Query Builder vs Raw SQL (Senior Decision)
কখন কোনটা ব্যবহার করবেন?
| Feature | ORM (Prisma/TypeORM) | Raw SQL |
|---|---|---|
| Development Speed | 🚀 খুব ফাস্ট | 🐢 স্লো |
| Complex Queries | ❌ কঠিন | ✅ ফুল কন্ট্রোল |
| Performance | হেভি ডেটায় স্লো | ✅ সুপার ফাস্ট |
💡 Best Practice: সাধারণ CRUD অপারেশনের জন্য ORM ব্যবহার করুন, কিন্তু জটিল রিপোর্টিং বা পারফরম্যান্স ক্রিটিক্যাল জায়গায় Raw SQL লিখুন।
২১.৮ Migration Strategy (DB Version Control)
টিমের সবাই যাতে একই ডেটাবেস স্ট্রাকচার পায়, তার জন্য মাইগ্রেশন বাধ্যতামূলক।
🎯 নিয়ম:
- কখনোই ম্যানুয়ালি প্রোডাকশন ডেটাবেসে কলাম অ্যাড করবেন না
- সবসময়
up(তৈরি) এবংdown(মুছে ফেলা) স্ক্রিপ্ট লিখুন - বড় টেবিলে কলাম অ্যাড করার সময়
pt-online-schema-changeবাgh-ostব্যবহার করুন
২১.৯ Connection Leak (Developer's Nightmare)
যদি আপনি conn.release() করতে ভুলে যান, তবে কানেকশনটি পুলের বাইরে ঝুলে থাকবে।
একসময় পুল খালি হয়ে যাবে এবং সার্ভার হ্যাং করবে (Error: Connection limit reached)।
✅ সমাধান:
সবসময় try...finally ব্লক ব্যবহার করুন। finally ব্লকে রিলিজ নিশ্চিত করুন।
let conn;
try {
conn = await pool.getConnection();
await doWork(conn);
} finally {
if (conn) conn.release(); // সবসময় রিলিজ হবে
}
২১.১০ Backend Error Handling Cheat Sheet
| MySQL Error Code | মানে কী? | ব্যাকএন্ড অ্যাকশন |
|---|---|---|
| 1213 (Deadlock) | ডেডলক হয়েছে | ট্রানজেকশন রি-ট্রাই করুন |
| 1062 (Duplicate) | ডুপ্লিকেট ডেটা | "Already exists" মেসেজ দিন |
| 1040 (Connections) | কানেকশন ফুল | পুল সাইজ বাড়ান |
| 1452 (Foreign Key) | ফরেন কি মিসিং | ইনপুট ভ্যালিডেশন চেক করুন |
২১.১১ Real-World Optimizations (Summary)
- 🔍Product Search: LIKE কুয়েরি বাদ দিয়ে Full-Text Search বা Elasticsearch ব্যবহার করুন
- 📊Dashboard: লাইভ COUNT(*) না চালিয়ে সামারি টেবিল বা রেডিস কাউন্টার ব্যবহার করুন
- 📦Bulk Insert: লুপের বদলে বাল্ক ইনসার্ট ব্যবহার করুন:
INSERT INTO ... VALUES (...), (...) - ⚡Indexing: স্লো কুয়েরি লগ দেখে শুধুমাত্র প্রয়োজনীয় কলামে ইনডেক্স দিন
🎯 অধ্যায় ২১ এর সারাংশ (Summary)
এই অধ্যায়ে আমরা শিখলাম:
- ✓Connection Pool: কেন এবং কীভাবে কনফিগার করতে হয়
- ✓Prepared Statements: SQL Injection থেকে বাঁচার একমাত্র উপায়
- ✓N+1 Problem: লুপের ভেতরে কুয়েরি = মৃত্যুদণ্ড
- ✓Keyset Pagination: OFFSET বাদ দিন, O(1) পেজিনেশন পান
- ✓Deadlock Retry: ৩ বার চেষ্টা করুন, তারপর থ্রো করুন
🏆 "MySQL: Beginner to Senior" জার্নি এখানেই অফিশিয়ালি শেষ! 🎉
আপনি এখন ডেটাবেস ডিজাইন, অপটিমাইজেশন, আর্কিটেকচার এবং ব্যাকএন্ড ইন্টিগ্রেশন—সবকিছুতেই দক্ষ। 💪