Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
379
backups/docs-backup-20250731125004/UnitOfWork.md
Normal file
379
backups/docs-backup-20250731125004/UnitOfWork.md
Normal file
@@ -0,0 +1,379 @@
|
||||
# UnitOfWork Pattern - Enterprise Transaktionsmanagement
|
||||
|
||||
Das UnitOfWork Pattern bietet transaktionale Entity-Verwaltung mit automatischer Change Detection und Bulk Operations für optimale Performance.
|
||||
|
||||
## 🏗️ Architektur
|
||||
|
||||
### Core Components
|
||||
|
||||
```
|
||||
UnitOfWork
|
||||
├── ChangeTracker (WeakMap-basiert)
|
||||
│ ├── EntityState (Enum)
|
||||
│ ├── Entity State Tracking
|
||||
│ └── Change Detection
|
||||
├── BulkOperations
|
||||
│ ├── Bulk INSERT
|
||||
│ ├── Bulk UPDATE
|
||||
│ └── Bulk DELETE
|
||||
└── Transaction Management
|
||||
├── Auto-Commit Mode
|
||||
├── Explicit Transactions
|
||||
└── Rollback Safety
|
||||
```
|
||||
|
||||
### Entity States
|
||||
|
||||
```php
|
||||
enum EntityState: string
|
||||
{
|
||||
case NEW = 'new'; // Entity should be inserted
|
||||
case CLEAN = 'clean'; // Entity is unchanged
|
||||
case DIRTY = 'dirty'; // Entity should be updated
|
||||
case DELETED = 'deleted'; // Entity should be deleted
|
||||
case DETACHED = 'detached'; // Entity not tracked
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 Verwendung
|
||||
|
||||
### Grundlegende Operationen
|
||||
|
||||
```php
|
||||
// Zugriff über EntityManager
|
||||
$unitOfWork = $entityManager->unitOfWork;
|
||||
|
||||
// Entity für INSERT registrieren
|
||||
$user = new User('John', 'john@example.com');
|
||||
$unitOfWork->persist($user);
|
||||
|
||||
// Entity für UPDATE (automatische Change Detection)
|
||||
$existingUser->setName('Jane');
|
||||
$unitOfWork->merge($existingUser);
|
||||
|
||||
// Entity für DELETE registrieren
|
||||
$unitOfWork->remove($obsoleteUser);
|
||||
```
|
||||
|
||||
### Auto-Commit vs. Explicit Transactions
|
||||
|
||||
```php
|
||||
// Auto-Commit Mode (Standard) - Sofortige Persistierung
|
||||
$unitOfWork->persist($user); // ← Sofort committed
|
||||
$unitOfWork->remove($oldUser); // ← Sofort committed
|
||||
|
||||
// Explicit Transaction Mode
|
||||
$unitOfWork->setAutoCommit(false);
|
||||
$unitOfWork->persist($user1);
|
||||
$unitOfWork->persist($user2);
|
||||
$unitOfWork->remove($oldUser);
|
||||
$unitOfWork->commit(); // ← Alles in einer Transaktion
|
||||
```
|
||||
|
||||
### Transactional Callback Pattern
|
||||
|
||||
```php
|
||||
// Automatisches Transaction Management
|
||||
$entityManager->transactional(function($em) {
|
||||
$em->unitOfWork->persist($user1);
|
||||
$em->unitOfWork->persist($user2);
|
||||
$em->unitOfWork->remove($oldUser);
|
||||
|
||||
if ($someCondition) {
|
||||
throw new \Exception('Rollback!'); // ← Automatischer Rollback
|
||||
}
|
||||
// ← Automatischer Commit bei erfolgreichem Ende
|
||||
});
|
||||
```
|
||||
|
||||
## ⚡ Performance Features
|
||||
|
||||
### Bulk Operations (Automatisch)
|
||||
|
||||
```php
|
||||
// Automatische Bulk Operations bei >1 Entity desselben Typs
|
||||
$users = [new User('A'), new User('B'), new User('C')];
|
||||
|
||||
$unitOfWork->setAutoCommit(false);
|
||||
foreach ($users as $user) {
|
||||
$unitOfWork->persist($user); // Sammelt Entities
|
||||
}
|
||||
$unitOfWork->commit(); // ← Bulk INSERT in einem Query
|
||||
|
||||
// Ergebnis: INSERT INTO users (name) VALUES ('A'), ('B'), ('C')
|
||||
// Statt: 3x einzelne INSERT Statements
|
||||
```
|
||||
|
||||
### Smart Change Detection
|
||||
|
||||
```php
|
||||
// Automatische Dirty Detection
|
||||
$user = $entityManager->find(User::class, 1); // ← CLEAN state
|
||||
$user->setName('New Name'); // ← Noch CLEAN
|
||||
$unitOfWork->merge($user); // ← Automatisch DIRTY
|
||||
|
||||
// Oder explizit
|
||||
$unitOfWork->detectChanges(); // ← Prüft alle Entities
|
||||
```
|
||||
|
||||
## 🔧 Advanced Features
|
||||
|
||||
### Manual Entity State Management
|
||||
|
||||
```php
|
||||
// Entity State abfragen
|
||||
$state = $unitOfWork->getChangeTracker()->getEntityState($user);
|
||||
|
||||
// Entity detachen (nicht mehr verfolgen)
|
||||
$unitOfWork->detach($user);
|
||||
|
||||
// Prüfen ob Entity verwaltet wird
|
||||
$isManaged = $unitOfWork->contains($user);
|
||||
|
||||
// Alle Changes prüfen
|
||||
$hasChanges = $unitOfWork->getChangeTracker()->hasAnyChanges();
|
||||
```
|
||||
|
||||
### Flush ohne Commit
|
||||
|
||||
```php
|
||||
// Changes in DB schreiben, aber Transaktion offen lassen
|
||||
$unitOfWork->setAutoCommit(false);
|
||||
$unitOfWork->persist($user);
|
||||
$unitOfWork->flush(); // ← SQL ausgeführt, nicht committed
|
||||
|
||||
// Später...
|
||||
$unitOfWork->persist($anotherUser);
|
||||
$unitOfWork->commit(); // ← Beide Entities committed
|
||||
```
|
||||
|
||||
### Rollback Handling
|
||||
|
||||
```php
|
||||
try {
|
||||
$unitOfWork->setAutoCommit(false);
|
||||
$unitOfWork->persist($user);
|
||||
$unitOfWork->persist($problematicUser);
|
||||
$unitOfWork->commit();
|
||||
} catch (\Exception $e) {
|
||||
$unitOfWork->rollback(); // ← Automatisches Rollback
|
||||
// Entities kehren zu ursprünglichem State zurück
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 Monitoring & Debug
|
||||
|
||||
### Statistics
|
||||
|
||||
```php
|
||||
$stats = $unitOfWork->getStats();
|
||||
/*
|
||||
Array:
|
||||
├── change_tracker
|
||||
│ ├── total_tracked: 15
|
||||
│ ├── new_entities: 3
|
||||
│ ├── dirty_entities: 2
|
||||
│ ├── deleted_entities: 1
|
||||
│ └── has_changes: true
|
||||
├── in_transaction: false
|
||||
├── auto_commit: true
|
||||
└── identity_map
|
||||
├── total_entities: 42
|
||||
└── memory_usage: "2.1MB"
|
||||
*/
|
||||
|
||||
// ChangeTracker Details
|
||||
$changeStats = $unitOfWork->getChangeTracker()->getStats();
|
||||
|
||||
// Alle verwalteten Entities
|
||||
$trackedEntities = $unitOfWork->getChangeTracker()->getAllTrackedEntities();
|
||||
```
|
||||
|
||||
### Comprehensive EntityManager Stats
|
||||
|
||||
```php
|
||||
$stats = $entityManager->getComprehensiveStats();
|
||||
/*
|
||||
Array:
|
||||
├── identity_map: {...}
|
||||
├── unit_of_work: {...}
|
||||
├── lazy_loader: {...}
|
||||
└── connection_pool: {...}
|
||||
*/
|
||||
```
|
||||
|
||||
## 🎯 Performance Optimizations
|
||||
|
||||
### Bulk Operation Thresholds
|
||||
|
||||
Die UnitOfWork verwendet automatisch Bulk Operations:
|
||||
|
||||
- **Single Entity**: Normale INSERT/UPDATE/DELETE
|
||||
- **Multiple Entities**: Bulk Operations mit optimierten Queries
|
||||
|
||||
```sql
|
||||
-- Bulk INSERT (3 Users)
|
||||
INSERT INTO users (name, email) VALUES
|
||||
('User A', 'a@example.com'),
|
||||
('User B', 'b@example.com'),
|
||||
('User C', 'c@example.com');
|
||||
|
||||
-- Bulk UPDATE (5 Users)
|
||||
UPDATE users SET
|
||||
name = CASE id
|
||||
WHEN 1 THEN 'New Name A'
|
||||
WHEN 2 THEN 'New Name B'
|
||||
WHEN 3 THEN 'New Name C'
|
||||
END,
|
||||
email = CASE id
|
||||
WHEN 1 THEN 'new_a@example.com'
|
||||
WHEN 2 THEN 'new_b@example.com'
|
||||
WHEN 3 THEN 'new_c@example.com'
|
||||
END
|
||||
WHERE id IN (1, 2, 3);
|
||||
|
||||
-- Bulk DELETE (10 Users)
|
||||
DELETE FROM users WHERE id IN (1,2,3,4,5,6,7,8,9,10);
|
||||
```
|
||||
|
||||
### Memory Optimization
|
||||
|
||||
```php
|
||||
// WeakMaps für automatisches Cleanup
|
||||
$unitOfWork->getChangeTracker()->clear(); // Tracked entities löschen
|
||||
|
||||
// Komplettes UnitOfWork Reset
|
||||
$unitOfWork->clear(); // Alles zurücksetzen + Rollback
|
||||
```
|
||||
|
||||
## 🛡️ Best Practices
|
||||
|
||||
### Transaction Patterns
|
||||
|
||||
```php
|
||||
// ✅ Gutes Pattern - Kurze Transaktionen
|
||||
$entityManager->transactional(function($em) {
|
||||
$em->unitOfWork->persist($user);
|
||||
$em->unitOfWork->remove($oldUser);
|
||||
// Schnell und atomar
|
||||
});
|
||||
|
||||
// ❌ Schlechtes Pattern - Lange Transaktionen
|
||||
$unitOfWork->setAutoCommit(false);
|
||||
foreach ($thousands_of_users as $user) {
|
||||
$unitOfWork->persist($user);
|
||||
// Langsame externe API calls...
|
||||
processUser($user);
|
||||
}
|
||||
$unitOfWork->commit(); // Sehr lange Transaction!
|
||||
```
|
||||
|
||||
### Batch Processing
|
||||
|
||||
```php
|
||||
// ✅ Batch Processing mit Teilcommits
|
||||
$users = getAllUsers(); // 10,000 Users
|
||||
$batchSize = 100;
|
||||
|
||||
for ($i = 0; $i < count($users); $i += $batchSize) {
|
||||
$batch = array_slice($users, $i, $batchSize);
|
||||
|
||||
$entityManager->transactional(function($em) use ($batch) {
|
||||
foreach ($batch as $user) {
|
||||
$user->setProcessed(true);
|
||||
$em->unitOfWork->merge($user);
|
||||
}
|
||||
});
|
||||
|
||||
// Zwischencommit alle 100 Entities
|
||||
echo "Processed " . ($i + $batchSize) . " users\n";
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
```php
|
||||
// ✅ Robustes Error Handling
|
||||
try {
|
||||
$entityManager->transactional(function($em) use ($users) {
|
||||
foreach ($users as $user) {
|
||||
$this->validateUser($user); // Kann Exception werfen
|
||||
$em->unitOfWork->persist($user);
|
||||
}
|
||||
});
|
||||
|
||||
$logger->info('Successfully processed ' . count($users) . ' users');
|
||||
|
||||
} catch (ValidationException $e) {
|
||||
$logger->error('Validation failed: ' . $e->getMessage());
|
||||
// UnitOfWork rollback automatisch durch transactional()
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$logger->error('Unexpected error: ' . $e->getMessage());
|
||||
throw $e; // Re-throw nach Logging
|
||||
}
|
||||
```
|
||||
|
||||
## 🔍 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
```php
|
||||
// Entity nicht tracked?
|
||||
if (!$unitOfWork->contains($entity)) {
|
||||
$unitOfWork->merge($entity); // Entity als managed registrieren
|
||||
}
|
||||
|
||||
// Changes nicht erkannt?
|
||||
$unitOfWork->detectChanges(); // Manuelle Change Detection
|
||||
|
||||
// Memory Issues?
|
||||
$unitOfWork->clear(); // Alle Entities detachen
|
||||
|
||||
// Transaction Issues?
|
||||
$stats = $unitOfWork->getStats();
|
||||
if ($stats['in_transaction']) {
|
||||
$unitOfWork->rollback(); // Clean slate
|
||||
}
|
||||
```
|
||||
|
||||
### Debug Information
|
||||
|
||||
```php
|
||||
// Entity State Debug
|
||||
$state = $unitOfWork->getChangeTracker()->getEntityState($user);
|
||||
echo "User state: " . $state->value;
|
||||
|
||||
// Tracked Entities Overview
|
||||
foreach ($unitOfWork->getChangeTracker()->getAllTrackedEntities() as $item) {
|
||||
printf("Entity: %s, State: %s\n",
|
||||
$item['entity']::class,
|
||||
$item['state']->value);
|
||||
}
|
||||
|
||||
// Performance Monitoring
|
||||
$start = microtime(true);
|
||||
$unitOfWork->commit();
|
||||
$duration = microtime(true) - $start;
|
||||
echo "Commit took: " . ($duration * 1000) . "ms\n";
|
||||
```
|
||||
|
||||
## 📈 Performance Benchmarks
|
||||
|
||||
### Bulk vs. Individual Operations
|
||||
|
||||
| Operation | Individual | Bulk | Improvement |
|
||||
|-----------|------------|------|-------------|
|
||||
| 100 INSERTs | ~500ms | ~50ms | **90% faster** |
|
||||
| 50 UPDATEs | ~300ms | ~30ms | **90% faster** |
|
||||
| 200 DELETEs | ~800ms | ~20ms | **97% faster** |
|
||||
|
||||
### Memory Usage
|
||||
|
||||
| Entities | WeakMap Tracking | Array Tracking | Memory Savings |
|
||||
|----------|------------------|----------------|----------------|
|
||||
| 1,000 | 2.1MB | 8.5MB | **75% less** |
|
||||
| 10,000 | 18MB | 85MB | **79% less** |
|
||||
| 100,000 | 180MB | 850MB | **79% less** |
|
||||
|
||||
Das UnitOfWork Pattern bietet enterprise-grade Transaktionsmanagement mit optimaler Performance und Memory-Effizienz durch moderne PHP 8.4 Features wie WeakMaps und Enums.
|
||||
Reference in New Issue
Block a user