Stop Leak, Close JDBC Resources
📖توضیحات درس
📄جزوه
مفاهیم کلیدی
-
JDBC Resources
منابعی مانندConnection،StatementوResultSetکه برای برقراری ارتباط و اجرای کوئری در پایگاه داده استفاده میشوند و باید پس از اتمام کار حتماً بسته شوند. -
Memory Leak (نشت حافظه)
اتفاقی که وقتی رخ میدهد که برنامه منابعی را اشغال کرده اما پس از اتمام کار آنها را آزاد نمیکند؛ این موضوع در درازمدت باعث پر شدن حافظه و کندی یا کرش کردن برنامه میشود. -
Idle Connection (اتصال بیکار)
اتصالی که به دیتابیس باز شده اما هیچ کوئری یا دستوری را اجرا نمیکند. این اتصالات همچنان منابع سرور (مانند RAM و CPU) را مصرف میکنند. -
Database Session
شاهراههایی که از سمت برنامه به پایگاه داده (مثلاً PostgreSQL) باز میشوند تا عملیات مورد نظر انجام شود. تعداد این سشنها در دیتابیس محدود است. -
Database Cursor
منابعی در سمت پایگاه داده که برای پیمایش روی نتایج کوئریها استفاده میشوند. عدم بستنResultSetمیتواند منجر به باز ماندن کرسرها و رسیدن به سقف مجاز آنها شود. -
Garbage Collector (GC)
بخشی از JVM که وظیفه پاکسازی اشیاء بدون استفاده در حافظه RAM را دارد، اما لزوماً بلافاصله منابع خارجی مثل سشنهای دیتابیس را آزاد نمیکند. -
Connection Pooling
مکانیزمی که در آن مجموعهای از کانکشنها از قبل ساخته شده و مدیریت میشوند تا به جای ساخت و حذف مداوم، از آنها دوباره استفاده شود که باعث بهبود پرفورمنس میشود.
نکات مهم مصاحبهای
-
چرا باید منابع JDBC را به صورت دستی Close کنیم؟
زیرا تکیه برGarbage Collectorبرای بستن منابع دیتابیسی اشتباه است. باز ماندن این منابع باعث اشغال سشنها، مصرف بیهوده RAM و CPU در سرور و در نهایت نشت حافظه میشود. -
ترتیب صحیح بستن منابع JDBC به چه صورت است؟
بهترین روش این است که منابع را به صورت عکسِ زمان ایجاد، ببندیم. یعنی ابتداResultSet، سپسStatement(یاPreparedStatement) و در نهایتConnection. -
اگر فقط Connection را ببندیم و ResultSet باز بماند چه اتفاقی میافتد؟
در برخی دیتابیسها و در حالت استفاده ازConnection Pooling، ممکن است کرسرهای دیتابیس باز بمانند و پس از مدتی با خطای "حداکثر تعداد کرسرها" مواجه شوید، زیرا منابع سمت سرور آزاد نشدهاند. -
تأثیر Idle Connection بر روی دیتابیس چیست؟
حتی اگر یک اتصال بیکار باشد، طبق بررسیهای فنی هر اتصال میتواند به طور میانگین بین ۱.۵ تا ۱۰ مگابایت (بسته به عملیات قبلی) از حافظه RAM سرور را اشغال کند.
مثال یا سناریوی کاربردی
تصور کنید برنامهای دارید که ۲۰۰۰ اتصال به دیتابیس باز میکند اما هیچکدام را نمیبندد. با ابزارهایی مثل VisualVM مشاهده خواهید کرد که مصرف حافظه Heap مدام بالا میرود. در سمت دیتابیس نیز لیست سشنها نشاندهنده ۲۰۰۰ اتصال در وضعیت Idle است.
برای حل این مشکل، باید متدی برای بستن منابع (Clean-up) بنویسیم. برای مثال در یک متد save :
public int save(User user) {
Connection connection = null;
PreparedStatement ps = null;
int result = -1;
try {
connection = JDBCConnection.getConnection();
ps = connection.prepareStatement("INSERT INTO users ...");
// اجرای کوئری
result = ps.executeUpdate();
} finally {
// بستن منابع در بخش نهایی برای امنیت کامل
if (ps != null) ps.close();
if (connection != null) connection.close();
}
return result;
}
در این سناریو، به محض اتمام کار، منابع آزاد شده و سشنهای دیتابیس بسته میشوند تا برنامه دچار اختلال نشود.
بیشتر بدانید
- تکنیک Extract Method: برای جلوگیری از تکرار کد بستن منابع در همه متدها، بهتر است یک متد کمکی مثل
closeResourcesبسازید که انواع منابع را به عنوان ورودی گرفته و آنها را ببندد. - Import Static: در Java میتوانید متدهای استاتیک کلاسهای ابزاری (Utility) را به صورت
import staticتعریف کنید تا بدون نوشتن نام کلاس، مستقیماً از متدها استفاده کنید. - نکته در IntelliJ: استفاده از قابلیت
Refactor > Extract Methodبه شما کمک میکند کدهای تکراری برای بستن منابع را به سرعت به یک متد مجزا تبدیل کنید. - نکته امنیتی: همیشه بستن منابع را در بلوکهایی انجام دهید که از اجرای آنها اطمینان دارید (مانند
finally) تا حتی در صورت بروز خطا، نشت حافظه رخ ندهد.
