انتقل إلى المحتوى الرئيسي

الفصل 1: إعداد مصادر البيانات

مقدمة​

في كل مرة يتفاعل تطبيق Spring Boot الخاص بك مع قاعدة البيانات، فإنه يستخدم اتصالاً. ولكن من أين تأتي هذه الاتصالات؟ كيف تتم إدارتها؟ هذا هو دور مصدر البيانات.


🎯 أهداف الفصل​

في نهاية هذا الفصل، ستعرف:

  1. ✅ ما هو مصدر البيانات ولماذا هو مهم
  2. ✅ كيف يقوم Spring Boot بتكوين الاتصالات تلقائيًا
  3. ✅ تكوين HikariCP (المجموعة الافتراضية)
  4. ✅ تحسين الإعدادات للإنتاج
  5. ✅ تكوين مصادر بيانات متعددة

1. ما هو مصدر البيانات؟​

تعريف بسيط​

مصدر البيانات هو كائن يوفر اتصالات لقاعدة البيانات.

المشكلة بدون مجموعة اتصالات​

// ❌ ممارسة سيئة: اتصال جديد لكل طلب
public void getUser(Long id) {
Connection conn = DriverManager.getConnection(url, user, password);
// ... استخدام الاتصال
conn.close();
}

مشاكل:

  • إنشاء اتصال = 500ms إلى 1s (بطيء جدًا!)
  • 100 مستخدم متزامن = 100 اتصال = قاعدة بيانات مشبعة
  • عدم إعادة الاستخدام = إهدار الموارد

الحل: مجموعة اتصالات​

// ✅ ممارسة جيدة: إعادة استخدام الاتصالات
public void getUser(Long id) {
Connection conn = dataSource.getConnection(); // ← اتصال من المجموعة (< 1ms)
// ... استخدام الاتصال
conn.close(); // ← يعود إلى المجموعة (ليس مغلقًا حقًا)
}

فوائد:

  • اتصالات مسبقة الإنشاء = استجابة فورية
  • إعادة الاستخدام = حمل أقل على قاعدة البيانات
  • يحد من العدد الأقصى للاتصالات

2. HikariCP: المجموعة الافتراضية​

لماذا HikariCP؟​

يستخدم Spring Boot HikariCP (光 = "الضوء" باليابانية) لأنه:

  • 🚀 الأسرع (معايير مثبتة)
  • 💪 الأكثر موثوقية (يستخدم من قبل شركات كبيرة)
  • 🔧 سهل التكوين

التكوين التلقائي لـ Spring Boot​

عندما تضيف اعتماد قاعدة بيانات، يقوم Spring Boot بتكوين HikariCP تلقائيًا:

<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<!-- HikariCP مضمن تلقائيًا! -->
</dependency>

3. التكوين الأساسي​

التكوين الأدنى (H2)​

# application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

تكوين PostgreSQL​

# application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=postgres
spring.datasource.password=secret

تكوين MySQL​

# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=secret

4. تكوين HikariCP المتقدم​

الإعدادات الأساسية​

# application.properties

# حجم المجموعة
spring.datasource.hikari.minimum-idle=5 # الحد الأدنى للاتصالات المحفوظة
spring.datasource.hikari.maximum-pool-size=10 # الحد الأقصى للاتصالات

# المهلات الزمنية
spring.datasource.hikari.connection-timeout=30000 # الانتظار الأقصى للحصول على اتصال (30 ثانية)
spring.datasource.hikari.idle-timeout=600000 # الوقت قبل إغلاق اتصال غير مستخدم (10 دقائق)
spring.datasource.hikari.max-lifetime=1800000 # العمر الأقصى للاتصال (30 دقيقة)

# اسم المجموعة (للسجلات)
spring.datasource.hikari.pool-name=MyAppPool

تصور المجموعة​

┌─────────────────────────────────────────────────────┐
│ HikariCP Pool │
│ │
│ minimum-idle=5 maximum-pool-size=10 │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Conn1│ │Conn2│ │Conn3│ │Conn4│ │Conn5│ (idle) │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ + 5 اتصالات إضافية إذا لزم الأمر │
│ │
│ connection-timeout=30s (الانتظار الأقصى إذا كانت المجموعة ممتلئة) │
└─────────────────────────────────────────────────────┘

صيغة YAML (بديل)​

# application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: postgres
password: secret
hikari:
minimum-idle: 5
maximum-pool-size: 10
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
pool-name: MyAppPool

5. توصيات حسب البيئة​

التطوير (H2)​

# application-dev.properties
spring.datasource.url=jdbc:h2:mem:devdb
spring.datasource.hikari.minimum-idle=2
spring.datasource.hikari.maximum-pool-size=5

# تفعيل وحدة تحكم H2
spring.h2.console.enabled=true

الإنتاج (PostgreSQL)​

# application-prod.properties
spring.datasource.url=jdbc:postgresql://db.server.com:5432/proddb
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=50

# لا وحدة تحكم H2!
spring.h2.console.enabled=false

# التحقق من الاتصالات
spring.datasource.hikari.connection-test-query=SELECT 1

صيغة لحجم المجموعة الأقصى​

قاعدة عامة:
maximum-pool-size = (عدد وحدات المعالجة المركزية * 2) + عدد الأقراص

مثال:
- خادم مع 4 وحدات معالجة مركزية وقرص SSD واحد
- حجم المجموعة = (4 * 2) + 1 = 9 ≈ 10
تلميح

لا تبالغ في الحجم! مجموعة كبيرة جدًا يمكن أن تؤدي إلى تدهور الأداء لأن قاعدة البيانات يجب أن تدير الكثير من الاتصالات المتزامنة.


6. تكوين مصادر بيانات متعددة​

حالة الاستخدام​

أحيانًا، يجب على التطبيق الاتصال بـ عدة قواعد بيانات:

التكوين​

# application.properties

# مصدر البيانات الأساسي (PostgreSQL)
spring.datasource.primary.url=jdbc:postgresql://localhost:5432/usersdb
spring.datasource.primary.username=postgres
spring.datasource.primary.password=secret
spring.datasource.primary.driver-class-name=org.postgresql.Driver

# مصدر البيانات الثانوي (MySQL)
spring.datasource.secondary.url=jdbc:mysql://localhost:3306/productsdb
spring.datasource.secondary.username=root
spring.datasource.secondary.password=secret
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

تكوين Java​

@Configuration
public class DataSourceConfig {

// مصدر البيانات الأساسي
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}

// مصدر البيانات الثانوي
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}

الاستخدام مع JPA​

// تكوين EntityManager للبيانات الأساسية
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.repository.users",
entityManagerFactoryRef = "primaryEntityManager",
transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryDatabaseConfig {
// ... التكوين
}

// تكوين EntityManager للبيانات الثانوية
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.repository.products",
entityManagerFactoryRef = "secondaryEntityManager",
transactionManagerRef = "secondaryTransactionManager"
)
public class SecondaryDatabaseConfig {
// ... التكوين
}

7. مراقبة المجموعة​

عبر Actuator​

أضف Spring Boot Actuator لمراقبة المجموعة:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
# application.properties
management.endpoints.web.exposure.include=health,metrics
management.endpoint.health.show-details=always

المقاييس المتاحة​

# تحقق من المجموعة
GET /actuator/metrics/hikaricp.connections

# الاتصالات النشطة
GET /actuator/metrics/hikaricp.connections.active

# الاتصالات المعلقة
GET /actuator/metrics/hikaricp.connections.pending

# المهلات الزمنية
GET /actuator/metrics/hikaricp.connections.timeout

مثال على الاستجابة​

{
"name": "hikaricp.connections.active",
"measurements": [
{
"statistic": "VALUE",
"value": 3.0
}
],
"availableTags": [
{
"tag": "pool",
"values": ["MyAppPool"]
}
]
}

8. المشاكل الشائعة والحلول​

❌ مهلة الاتصال​

HikariPool-1 - Connection is not available, request timed out after 30000ms.

الأسباب:

  • مجموعة صغيرة جدًا
  • اتصالات غير مغلقة (تسرب)
  • طلبات بطيئة جدًا

الحلول:

# زيادة حجم المجموعة
spring.datasource.hikari.maximum-pool-size=20

# زيادة المهلة
spring.datasource.hikari.connection-timeout=60000

# تفعيل سجلات التسرب
spring.datasource.hikari.leak-detection-threshold=60000

❌ عدد كبير جدًا من الاتصالات​

PostgreSQL: FATAL: too many connections for role "postgres"

السبب: مجموعة كبيرة جدًا أو عدة مثيلات

الحل:

# تقليل حجم المجموعة
spring.datasource.hikari.maximum-pool-size=5

# تحقق من max_connections في PostgreSQL
# SHOW max_connections;

❌ تسرب الاتصال​

HikariPool-1 - Connection leak detection triggered

السبب: اتصال لم يتم إرجاعه إلى المجموعة

الحل:

# تفعيل اكتشاف التسرب
spring.datasource.hikari.leak-detection-threshold=30000

ثم العثور على الكود الخاطئ وتصحيحه (اتصال غير مغلق).


9. ملخص​

النقاط الرئيسية​

المفهومالوصف
مصدر البياناتيوفر الاتصالات لقاعدة البيانات
HikariCPمجموعة الاتصالات الافتراضية (الأسرع)
minimum-idleالحد الأدنى للاتصالات المحفوظة
maximum-pool-sizeالحد الأقصى للاتصالات
connection-timeoutالوقت الأقصى للحصول على اتصال

قائمة التحقق من التكوين​

✅ تحديد spring.datasource.url
✅ تحديد اسم المستخدم/كلمة المرور
✅ تكوين minimum-idle و maximum-pool-size
✅ ضبط المهلات الزمنية حسب البيئة
✅ المراقبة باستخدام Actuator

التكوين الموصى به​

# الإنتاج
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=myuser
spring.datasource.password=${DB_PASSWORD}

spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.pool-name=MyAppPool

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

الآن بعد أن فهمت كيف تتم إدارة الاتصالات، حان الوقت لتعلم كيفية حماية سلامة بياناتك باستخدام المعاملات.

➡️ الفصل 2: إدارة المعاملات (@Transactional)


⬅️ العودة إلى الوحدة 7