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.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:تهيئة الاتصال
انقل شهادة 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
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_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
src/main/java/com/example/todos/TodoRepository.java. يتولّى Spring Data تنفيذ هذه الواجهة تلقائيًا في وقت التشغيل:
src/main/java/com/example/todos/TodoRepository.java
src/main/java/com/example/todos/TodoController.java، بحيث يُجري كل مسار استدعاءً واحدًا للمستودع:
src/main/java/com/example/todos/TodoController.java
@Transactional.
التشغيل والتحقق
اضبط كلمة المرور ثم شغّل التطبيق:POST الصفوف الجديدة، بينما يُعيد طلب PATCH الصف المُحدَّث. ويُضيف الخيار -w '\n' سطرًا جديدًا بعد كل استجابة:
pg_stat_ssl أثناء تشغيل التطبيق:
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 الذي ينفذها، وقد تتسرب إلى عملاء آخرين. كما تفشل معلمتا URLcurrentSchemaو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 خاطئة.
الخطوات التالية
- الاتصال: سلاسل الاتصال وPgBouncer وTLS
- الإعدادات: معلمات Postgres وPgBouncer، مثل
max_connections - النسخ المتماثلة للقراءة: توجيه استعلامات القراءة فقط إلى نسخة متماثلة
- الأمان: قوائم التحكم في الوصول حسب عناوين IP والشبكات الخاصة