الاتصال بقاعدة البيانات
الاتصال بقاعدة البيانات
قبل أن تتمكّن من تنفيذ جملة SQL واحدة تحتاج إلى كائن Connection حي. تمنحك JDBC آليتين مختلفتين للحصول عليه: الفئة منخفضة المستوى DriverManager والواجهة رفيعة المستوى DataSource. إنّ فهم الاثنتين — ومعرفة متى تستخدم كلًّا منهما — هو أساس كل ما يأتي في هذا البرنامج التعليمي.
كيف تحمّل JDBC برنامج التشغيل
برنامج تشغيل JDBC ما هو إلا ملف JAR في مسار الفئات يحتوي على فئة تنفّذ الواجهة java.sql.Driver. منذ JDBC 4.0 (Java 6)، يُسجّل برنامج التشغيل نفسَه تلقائيًا عبر آلية مزوّد الخدمة (SPI): يتضمّن ملف JAR ملفًا باسم META-INF/services/java.sql.Driver يسرد فئة التشغيل، ويقرأه DriverManager عند بدء التشغيل. لم تعد بحاجة إلى كتابة Class.forName("com.mysql.cj.jdbc.Driver") — وإن كنت قد تراه في الكود القديم.
mysql-connector-j عبر Maven/Gradle) إلى مشروعك وسيُكتشف تلقائيًا. لا حاجة لأي كود تسجيل يدوي.
DriverManager — الأسلوب البسيط
يُعدّ DriverManager.getConnection(url, user, password) أكثر طريقة مباشرة للحصول على اتصال. فهو يتكرّر على المشغّلات المسجّلة ويسأل كلًّا منها ما إذا كان يفهم عنوان URL الذي أمدّه به.
يضمن حقل try-with-resources إغلاق الاتصال حتى في حالة رمي استثناء. لا تُهمل هذا أبدًا — فالاتصال غير المغلق يُسرّب مقبسًا (socket) وجلسةً على جانب الخادم.
تشريح عنوان URL الخاص بـ JDBC
يتبع كل عنوان JDBC النمط jdbc:<subprotocol>:<subname>. يُحدّد البروتوكول الفرعي المشغّل؛ أما الاسم الفرعي فيعتمد على المشغّل. أمثلة شائعة:
- MySQL / MariaDB:
jdbc:mysql://host:3306/dbname?param=value - PostgreSQL:
jdbc:postgresql://host:5432/dbname - H2 (في الذاكرة، مثالية للاختبارات):
jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 - SQLite:
jdbc:sqlite:/path/to/file.db
تختلف معاملات سلسلة الاستعلام بحسب المشغّل لكنها تشمل في الغالب:
useSSL=true/sslmode=require— تشفير الاتصال (استخدمه دائمًا في الإنتاج).serverTimezone=UTC(MySQL) — يمنع أخطاء التفاوض على المنطقة الزمنية.connectTimeout=5000— الحد الأقصى بالمللي ثانية للانتظار حتى اكتمال المصافحة TCP.
لماذا لا يكفي DriverManager في التطبيقات الحقيقية
فتح اتصال TCP جديد لكل استدعاء قاعدة بيانات عملية مكلفة — تستغرق عادةً من 20 إلى 100 مللي ثانية على شبكة محلية. تحت أي حمل يُعتدّ به، سيُنهك تطبيق ويب يستخدم DriverManager مباشرةً إما حدود اتصال قاعدة البيانات أو يُنشئ زمن استجابة مرتفع غير مقبول. هذه هي المشكلة التي يحلّها تجميع الاتصالات (connection pooling)، وهو ما تعرضه واجهة DataSource.
DataSource — الأسلوب للإنتاج
تُعدّ javax.sql.DataSource (جزء من JDBC API) مصنعًا يوزّع الاتصالات المُنشأة مسبقًا من تجمّع (pool). من وجهة نظر الكود المُستدعي تكاد الواجهة البرمجية متطابقة — تستدعي dataSource.getConnection() بدلًا من DriverManager.getConnection(...) — لكن خلف الكواليس يأتي الاتصال من تجمّع قابل لإعادة الاستخدام لا من مقبس TCP جديد.
التنفيذ الأكثر استخدامًا لـ DataSource هو HikariCP، المعروف بتكلفته المنخفضة والتحقق الصارم منه. أضفه إلى ملف البناء:
إعداده واستخدامه:
يستعير كل مُستدعٍ الاتصالات ويعيدها عبر التجمّع:
close() دائمًا (أو استخدم try-with-resources). مع التجمّع، لا تُدمّر close() مقبس TCP — بل تُعلّم الاتصال باعتباره متاحًا ثانيةً. نسيانها يُجفّف التجمّع تمامًا كما يفعل التسريب الحقيقي.
DriverManager مقابل DataSource — متى تستخدم أيًّا منهما
- DriverManager: السكريبتات والأدوات التي تُنفَّذ مرة واحدة واختبارات الوحدة التي تُنشئ اتصالًا واحدًا. سهل الإعداد ولا يحتاج تبعيات فوق JAR التشغيل.
- DataSource (مُجمَّع): كل تطبيق على جانب الخادم وكل خدمة تتعامل مع أكثر من طلب في آنٍ واحد. زمن استجابة أقل وحدود قابلة للضبط وفحص صحة وإيقاف تشغيل متحكَّم به.
عمليًا، تُهيّئ أُطر العمل كـ Spring Boot كائن DataSource مُجمَّعًا تلقائيًا من application.properties. إنّ فهم ما تُعدّه — HikariCP افتراضيًا — هو ما يُتيح لك ضبطه واستكشاف أخطائه.
الخلاصة
DriverManager أداتك للبدء السريع: أمدّه بعنوان URL واسم المستخدم وكلمة المرور واحصل على اتصال. لأي حمل حقيقي، استبدله بـ DataSource مُجمَّعة (HikariCP هو الاختيار المعياري). يعرض الاثنان كائن Connection الذي تستخدمه بشكل متطابق من هذه النقطة فصاعدًا — دائمًا داخل حقل try-with-resources. في الدرس القادم ستستخدم هذا الاتصال لتنفيذ جمل SQL.