|  | 
| 14 | 14 | Built on top of PDO with **zero external dependencies**, it offers: | 
| 15 | 15 | - **Fluent Query Builder** - Intuitive, chainable API for all database operations | 
| 16 | 16 | - **Cross-Database Compatibility** - Automatic SQL dialect handling (MySQL, PostgreSQL, SQLite) | 
|  | 17 | +- **Read/Write Splitting** - Horizontal scaling with master-replica architecture and load balancing | 
| 17 | 18 | - **JSON Operations** - Native JSON support with consistent API across all databases | 
| 18 | 19 | - **Query Caching** - PSR-16 integration for result caching (10-1000x faster queries) | 
| 19 | 20 | - **Advanced Pagination** - Full, simple, and cursor-based pagination with metadata | 
| @@ -42,6 +43,7 @@ Inspired by [ThingEngineer/PHP-MySQLi-Database-Class](https://github.com/ThingEn | 
| 42 | 43 |   - [PostgreSQL Configuration](#postgresql-configuration) | 
| 43 | 44 |   - [SQLite Configuration](#sqlite-configuration) | 
| 44 | 45 |   - [Connection Pooling](#connection-pooling) | 
|  | 46 | +  - [Read/Write Splitting](#readwrite-splitting) | 
| 45 | 47 | - [Quick Start](#quick-start) | 
| 46 | 48 |   - [Basic CRUD Operations](#basic-crud-operations) | 
| 47 | 49 |   - [Filtering and Joining](#filtering-and-joining) | 
| @@ -314,6 +316,81 @@ $users = $db->connection('mysql_main')->find()->from('users')->get(); | 
| 314 | 316 | $stats = $db->connection('pgsql_analytics')->find()->from('stats')->get(); | 
| 315 | 317 | ``` | 
| 316 | 318 | 
 | 
|  | 319 | +### Read/Write Splitting | 
|  | 320 | + | 
|  | 321 | +Scale horizontally with master-replica architecture. Automatically route reads to replicas and writes to master: | 
|  | 322 | + | 
|  | 323 | +```php | 
|  | 324 | +use tommyknocker\pdodb\PdoDb; | 
|  | 325 | +use tommyknocker\pdodb\connection\loadbalancer\RoundRobinLoadBalancer; | 
|  | 326 | + | 
|  | 327 | +$db = new PdoDb(); | 
|  | 328 | + | 
|  | 329 | +// Enable read/write splitting with load balancer | 
|  | 330 | +$db->enableReadWriteSplitting(new RoundRobinLoadBalancer()); | 
|  | 331 | + | 
|  | 332 | +// Add write connection (master) | 
|  | 333 | +$db->addConnection('master', [ | 
|  | 334 | +    'driver' => 'mysql', | 
|  | 335 | +    'host' => 'master.db.local', | 
|  | 336 | +    'username' => 'user', | 
|  | 337 | +    'password' => 'pass', | 
|  | 338 | +    'dbname' => 'myapp', | 
|  | 339 | +    'type' => 'write', | 
|  | 340 | +]); | 
|  | 341 | + | 
|  | 342 | +// Add read connections (replicas) | 
|  | 343 | +$db->addConnection('replica-1', [ | 
|  | 344 | +    'driver' => 'mysql', | 
|  | 345 | +    'host' => 'replica1.db.local', | 
|  | 346 | +    'username' => 'user', | 
|  | 347 | +    'password' => 'pass', | 
|  | 348 | +    'dbname' => 'myapp', | 
|  | 349 | +    'type' => 'read', | 
|  | 350 | +]); | 
|  | 351 | + | 
|  | 352 | +$db->addConnection('replica-2', [ | 
|  | 353 | +    'driver' => 'mysql', | 
|  | 354 | +    'host' => 'replica2.db.local', | 
|  | 355 | +    'username' => 'user', | 
|  | 356 | +    'password' => 'pass', | 
|  | 357 | +    'dbname' => 'myapp', | 
|  | 358 | +    'type' => 'read', | 
|  | 359 | +]); | 
|  | 360 | + | 
|  | 361 | +$db->connection('master'); | 
|  | 362 | + | 
|  | 363 | +// SELECT queries automatically go to read replicas | 
|  | 364 | +$users = $db->find()->from('users')->get(); | 
|  | 365 | + | 
|  | 366 | +// INSERT/UPDATE/DELETE automatically go to write master | 
|  | 367 | +$id = $db->find()->table('users')->insert(['name' => 'John', 'email' => 'john@example.com']); | 
|  | 368 | + | 
|  | 369 | +// Force a SELECT to read from master | 
|  | 370 | +$user = $db->find()->from('users')->forceWrite()->where('id', $id)->getOne(); | 
|  | 371 | + | 
|  | 372 | +// Enable sticky writes (reads go to master for 60s after writes) | 
|  | 373 | +$db->enableStickyWrites(60); | 
|  | 374 | +``` | 
|  | 375 | + | 
|  | 376 | +**Load Balancing Strategies:** | 
|  | 377 | +- `RoundRobinLoadBalancer` - Distributes requests evenly in circular order | 
|  | 378 | +- `RandomLoadBalancer` - Randomly selects a replica | 
|  | 379 | +- `WeightedLoadBalancer` - Distributes proportionally based on weights | 
|  | 380 | + | 
|  | 381 | +**Key Features:** | 
|  | 382 | +- Automatic query routing (SELECTs → replicas, DML → master) | 
|  | 383 | +- Sticky writes for read-after-write consistency | 
|  | 384 | +- Multiple load balancing strategies | 
|  | 385 | +- Health checks and automatic failover | 
|  | 386 | +- Transaction support (always uses master) | 
|  | 387 | + | 
|  | 388 | +See: | 
|  | 389 | +- [Documentation: Read/Write Splitting](documentation/05-advanced-features/read-write-splitting.md) | 
|  | 390 | +- [Example: Basic Setup](examples/15-read-write-splitting/01-basic-setup.php) | 
|  | 391 | +- [Example: Sticky Writes](examples/15-read-write-splitting/02-sticky-writes.php) | 
|  | 392 | +- [Example: Load Balancers](examples/15-read-write-splitting/03-load-balancers.php) | 
|  | 393 | + | 
| 317 | 394 | --- | 
| 318 | 395 | 
 | 
| 319 | 396 | ## Quick Start | 
|  | 
0 commit comments