Skip to main content
يتصل Spring Boot بـ Postgres عبر مشغّل JDBC الخاص بـ PostgreSQL ‏(pgjdbc) ومجمّع الاتصالات HikariCP، ويُنفّذ عمليات الترحيل الخاصة بـ Flyway عند بدء تشغيل التطبيق. في هذا الدليل، ستُنشئ جدول todos باستخدام عملية ترحيل في Flyway، ثم تعالج طلبات الإنشاء والقراءة والتحديث والحذف عبر وحدة تحكم REST مبنية على Spring Data JPA. يستخدم كل اتصال بروتوكول TLS مع تحقق كامل من الشهادة.

المتطلبات الأساسية

  • JDK 17 أو إصدار أحدث، كما يشترط Spring Boot 4. جرى اختبار هذا الدليل باستخدام Java 25 وSpring Boot 4.1.1 وpgjdbc 42.7.13 وHibernate 7.4.5 وHikariCP 7.0.2 وFlyway 12.4.0.
  • حساب على ClickHouse Cloud
  • psql لإنشاء قاعدة البيانات. ويمكنك أيضًا تنفيذ عبارة CREATE DATABASE في SQL console.

إنشاء خدمة ClickHouse Managed Postgres

في وحدة تحكم ClickHouse Cloud، انقر على New service ثم اختر Postgres. يصبح المثيل جاهزًا في غضون دقائق قليلة. للاطلاع على شرح مفصّل للخطوات، راجع دليل البدء السريع.

الحصول على بيانات الاتصال

انقر على Connect في الشريط الجانبي الأيسر لخدمتك. تعرض النافذة المنبثقة اسم المستخدم وكلمة المرور والخادم والمنفذ، كما تتضمن مفتاح تبديل بين Directly وvia PgBouncer. بعد تحديد Directly، فعّل Use SSL وافتح علامة التبويب jdbc. ستجد فيها عنوان JDBC URL يمكنك استخدامه في Spring Boot بعد إجراء تعديلين عليه، ستُجريهما في قسم تهيئة الاتصال، وهما: اسم قاعدة البيانات واسم ملف شهادة CA.
لا يتضمن عنوان JDBC URL اسم المستخدم وكلمة المرور، إذ يقرأهما Spring Boot من خصائص منفصلة. يتصل هذا الدليل مباشرةً بـ Postgres عبر المنفذ 5432. تطبيق Spring Boot عملية طويلة الأمد تحتفظ بمجمّع اتصالات HikariCP خاص بها، يضم 10 اتصالات افتراضيًا، لذا لا حاجة إلى وسيط تجميع اتصالات ثانٍ أمام Postgres. احرص على أن يبقى حاصل ضرب عدد مثيلات التطبيق في حجم مجمّع الاتصالات أقل من قيمة max_connections الخاصة بالخدمة. وإذا كنت تشغّل عددًا كبيرًا من المثيلات، فراجع استخدام PgBouncer. في النافذة المنبثقة، انقر على Download CA certificate. ويمكنك أيضًا تنزيلها من Settings → CA Certificate. هذه الشهادة مميزة لمثيلك، ما يتيح للمشغّل استخدامها للتحقق من أنه يتصل بخادمك أنت.

إعداد المشروع

أنشئ مشروع Maven باستخدام Spring Initializr مع إضافة التبعيات Spring Web وSpring Data JPA وFlyway Migration وPostgreSQL Driver:
هل تعمل على تطبيق موجود؟تخطَّ أمر curl. أضف إلى ملف pom.xml التبعيات spring-boot-starter-data-jpa وspring-boot-starter-flyway وorg.flywaydb:flyway-database-postgresql، إضافةً إلى org.postgresql:postgresql بنطاق runtime، واحذف com.h2database:h2 إن كان تطبيقك يستخدم H2. بعد ذلك، انتقل إلى تهيئة الاتصال.

تهيئة الاتصال

انقل شهادة CA التي نزّلتها إلى دليل المشروع، وأعِد تسميتها إلى ca-certificate.pem. أنشئ قاعدة بيانات للتطبيق. استبدل <PASSWORD> والمضيف بالقيم الظاهرة في النافذة المنبثقة Connect:
استبدل محتويات src/main/resources/application.properties بما يلي. أما إذا كان لديك تطبيق قائم، فأضف أسطر spring.datasource وspring.jpa، واحذف أي إعدادات أخرى خاصة بـ spring.datasource، مثل عنوان URL الخاص بـ H2. عنوان URL المستخدم هنا هو نفسه الموجود في علامة التبويب jdbc، مع تغيير قاعدة البيانات إلى guide_spring وتعديل sslrootcert ليشير إلى الملف بعد إعادة تسميته:
src/main/resources/application.properties
يقرأ pgjdbc كلًّا من sslmode=verify-full وsslrootcert من عنوان URL، ويحمّل كل شهادة موجودة في ملف CA، ويتحقق من سلسلة الشهادات واسم المضيف معًا، لذا لا تحتاج إلى كتابة أي شيفرة TLS إضافية. أما Spring Boot فيقرأ كلمة المرور من متغير البيئة DATABASE_PASSWORD، فتبقى خارج الملف. أما بقية الإعدادات:
  • يجعل ddl-auto=validate أداة Hibernate تتحقق عند بدء التشغيل من تطابق الكيانات مع الجداول التي تنشئها Flyway، دون أن تُجري Hibernate أي تغيير على المخطط.
  • يُعيد open-in-view=false كل اتصال إلى مجمّع الاتصالات فور انتهاء معاملته، بدلًا من الاحتفاظ به إلى أن تُكتب استجابة HTTP.
يُحَلّ المسار النسبي في sslrootcert نسبةً إلى دليل العمل الخاص بـ JVM. ولأن الأمر ./mvnw spring-boot:run يشغّل التطبيق من دليل المشروع، فإن ca-certificate.pem يعمل هناك. أما عند تشغيل ملف JAR المُحزَّم من موضع آخر، فاستخدم مسارًا مطلقًا، إذ لا يوسّع pgjdbc الرمز ~.إذا نسخت عنوان URL مع إيقاف Use SSL، فلن يتضمن sslmode، وعندها يستخدم pgjdbc القيمة prefer؛ أي أنه يشفّر الاتصال لكنه لا يتحقق من الخادم. وعند استخدام CA غير صحيحة، يفشل الاتصال مع الرسالة PKIX path building failed. وإذا كان الملف مفقودًا، يفشل مع الرسالة Could not open SSL root certificate file. وإذا لم يطابق المضيف الشهادة، كما هو الحال عند الاتصال عبر عنوان IP، يفشل مع الرسالة The hostname ... could not be verified by hostnameverifier PgjdbcHostnameVerifier.

إنشاء الجدول باستخدام Flyway

يُنفّذ Flyway ملفات SQL الموجودة في src/main/resources/db/migration بحسب ترتيب إصداراتها عند بدء تشغيل التطبيق، أي قبل أن يتحقق Hibernate من صحة المخطط. أنشئ الملف src/main/resources/db/migration/V1__create_todos.sql:
src/main/resources/db/migration/V1__create_todos.sql
يسجّل Flyway كل ملف مُطبَّق في جدول flyway_schema_history، ولا يشغّل في مرات التشغيل اللاحقة سوى الملفات الجديدة. لتغيير المخطط، أضف ملفًا جديدًا مثل V2__add_due_date.sql بدلًا من تحرير ملف سبق تشغيله.
في التطبيقات التي كانت تستخدم H2، كان Hibernate يتولى عادةً إنشاء الجداول، لأن القيمة الافتراضية لـ ddl-auto في قواعد البيانات المضمّنة هي create-drop. أما في Postgres، فالقيمة الافتراضية هي none، لذا أضف ترحيلًا ينشئ جداولك الحالية. ويتطلب الحقل @Id المقترن بـ @GeneratedValue دون خيارات إضافية وجودَ تسلسل يحمل اسم الكيان، مثل employee_seq للكيان Employee، ويتزايد بمقدار 50، وهو حجم التخصيص الافتراضي في Hibernate. وإلا فسيفشل بدء التشغيل بالخطأ Schema validation: missing sequence [employee_seq]، أو بالخطأ The increment size of the [employee_seq] sequence is set to [50] in the entity mapping but the mapped database sequence increment size is [1] إذا كان التسلسل يتزايد بمقدار 1:

الاستعلام عن قاعدة البيانات

أنشئ الكيان في src/main/java/com/example/todos/Todo.java. يربط Spring Boot الحقل createdAt بالعمود created_at:
src/main/java/com/example/todos/Todo.java
أنشئ مستودع Spring Data في src/main/java/com/example/todos/TodoRepository.java. يتولّى Spring Data تنفيذ هذه الواجهة تلقائيًا في وقت التشغيل:
src/main/java/com/example/todos/TodoRepository.java
أنشئ وحدة تحكم REST في src/main/java/com/example/todos/TodoController.java، بحيث يُجري كل مسار استدعاءً واحدًا للمستودع:
src/main/java/com/example/todos/TodoController.java
يُنفَّذ كل استدعاء للمستودع ضمن معاملة مستقلة، على اتصال يُؤخذ من مجمّع اتصالات HikariCP. ولجمع عدة استدعاءات في معاملة واحدة، ضعها داخل طريقة موسومة بـ @Transactional.

التشغيل والتحقق

اضبط كلمة المرور ثم شغّل التطبيق:
عند التشغيل لأول مرة، يطبّق Flyway عملية الترحيل قبل أن يبدأ خادم الويب بالعمل. ويتضمن السجل الأسطر التالية، وقد عُرضت هنا دون الطوابع الزمنية وأسماء خيوط التنفيذ:
في طرفية ثانية، أنشئ مهمتين، ثم ضع علامة “مكتملة” على الأولى، واحذف الثانية:
تُعيد طلبات POST الصفوف الجديدة، بينما يُعيد طلب PATCH الصف المُحدَّث. ويُضيف الخيار -w '\n' سطرًا جديدًا بعد كل استجابة:
افتح http://localhost:3113/todos في متصفحك لعرض المهام المتبقية. ستظهر الاستجابة على النحو التالي:
للتحقق من أن اتصالات التطبيق تستخدم TLS، استعلم من pg_stat_ssl أثناء تشغيل التطبيق:
تمثّل الاتصالات العشرة مجمّع اتصالات HikariCP. أوقف التطبيق بالضغط على Ctrl+C. لعرض البيانات في الواجهة، افتح SQL console من الشريط الجانبي الأيسر لخدمتك، ثم وسّع guide_spring ثم public، وانقر على جدول todos. أما جدول flyway_schema_history المجاور له فيحتفظ بسجل عمليات الترحيل. ويحتوي جدول todos على الصف المتبقي:

استخدام PgBouncer

عندما يقترب العدد الإجمالي لاتصالات مثيلات التطبيق من حدّ اتصالات Postgres، اربط التطبيق عبر PgBouncer المضمَّن على المنفذ 6432، مع إبقاء Flyway على الاتصال المباشر. في الملف application.properties، غيّر المنفذ في spring.datasource.url إلى 6432، ثم أضف أسطر spring.flyway التالية أسفله:
src/main/resources/application.properties
عند تعيين spring.flyway.url، يفتح Flyway اتصالًا خاصًا به ولا يستخدم اسم المستخدم وكلمة المرور المحددين في spring.datasource، لذا عيِّن أيضًا spring.flyway.user وspring.flyway.password. وتصلح شهادة CA نفسها لكلا المنفذين. يعمل PgBouncer في وضع تجميع المعاملات، لذا قد تُنفَّذ كل معاملة على اتصال Postgres مختلف. وعند استخدام Spring Boot:
  • العبارات المُحضَّرة تعمل مع إعدادات المشغّل الافتراضية، فلا حاجة إلى prepareThreshold=0. فبدءًا من التنفيذ الخامس لعبارة ما على الاتصال نفسه (prepareThreshold)، يستخدم pgjdbc عبارة مُحضَّرة مُسمّاة على جانب الخادم. ويحرّر هذه العبارات عبر رسالة Close على مستوى البروتوكول، وهي رسالة يدعمها PgBouncer المرفق.
  • يلزم pgjdbc 42.7.5 أو أحدث، إذ ترسل الإصدارات الأقدم معلمة بدء التشغيل extra_float_digits، فيرفض PgBouncer الاتصال مع الخطأ FATAL: unsupported startup parameter: extra_float_digits. يتضمن Spring Boot 4 إصدارًا أحدث من pgjdbc. أما في إصدارات Spring Boot الأقدم، فعيِّن <postgresql.version>42.7.13</postgresql.version> في قسم <properties> من الملف pom.xml.
  • إعدادات الجلسة لا تُحفَظ. لا تنطبق عبارات SET وConnection.setSchema (التي تستخدمها الخاصية spring.datasource.hikari.schema في HikariCP) إلا على اتصال Postgres الذي ينفذها، وقد تتسرب إلى عملاء آخرين. كما تفشل معلمتا URL currentSchema وoptions مع الخطأ FATAL: unsupported startup parameter. لذا استخدم أسماء جداول مسبوقة باسم المخطط، أو SET LOCAL داخل معاملة.
  • Flyway يعمل عبر PgBouncer افتراضيًا، لأنه يحصل على قفل استشاري على مستوى المعاملة. أما عمليات الترحيل التي تنفذ CREATE INDEX CONCURRENTLY فتحتاج إلى spring.flyway.postgresql.transactional-lock=false، الذي يجعل Flyway يستخدم قفلًا على مستوى الجلسة. وعبر PgBouncer، يفشل تحرير هذا القفل مع الخطأ Unable to release PostgreSQL advisory lock ويبقى محتجزًا على أحد اتصالات المجمّع، لذا استخدم الاتصال المباشر مع Flyway.
  • حجم المجمّع: كل اتصال في HikariCP هو اتصال عميل منخفض الكلفة بـ PgBouncer. ويحدّ PgBouncer عدد اتصالات Postgres التي يفتحها لكل قاعدة بيانات ومستخدم (default_pool_size)، بصرف النظر عن عدد اتصالات العملاء التي تفتحها مثيلات تطبيقك. وتنتظر المعاملات التي تتجاوز هذا الحد في PgBouncer مدةً تصل إلى query_wait_timeout (‏120 ثانية افتراضيًا) بدلًا من أن تفشل في HikariCP. ولا يزيد توسيع مجمّع HikariCP التزامنَ إلا في حدود هذا الحد، لذا تُعد القيمة الافتراضية البالغة 10 لكل مثيل نقطة بداية مناسبة. راجع حدود اتصالات PgBouncer وPostgres.
يعرض pg_stat_ssl الاتصال بين PgBouncer وPostgres، لذا لا يُظهر استعلام TLS الوارد في التشغيل والتحقق اتصالات التطبيق عبر PgBouncer. ومع ذلك يظل اتصال التطبيق بـ PgBouncer خاضعًا للتحقق، إذ يفشل الاتصال بالطريقة نفسها عند استخدام شهادة CA خاطئة.

الخطوات التالية

آخر تعديل في ١٤ أكتوبر ٢٠٢٦