# AMPHP v3 — Database Patterns --- ## MySQL — connection pool setup ```php execute('SELECT id, name FROM users WHERE active = ?', [1]); foreach ($result as $row) { echo $row['id'] . ': ' . $row['name'] . "\n"; } // Fetch all rows at once (buffered) $rows = $pool->execute('SELECT * FROM products WHERE category_id = ?', [$categoryId]); $data = []; foreach ($rows as $row) { $data[] = $row; } ``` --- ## MySQL — transaction ```php beginTransaction(); try { $transaction->execute( 'INSERT INTO orders (user_id, total) VALUES (?, ?)', [$userId, $total], ); $result = $transaction->execute('SELECT LAST_INSERT_ID() AS id'); $orderId = $result->fetchRow()['id']; foreach ($items as $item) { $transaction->execute( 'INSERT INTO order_items (order_id, product_id, qty) VALUES (?, ?, ?)', [$orderId, $item['product_id'], $item['qty']], ); } $transaction->commit(); } catch (\Throwable $e) { $transaction->rollback(); throw $e; } ``` --- ## MySQL — prepared statement (reuse for many rows) ```php prepare('INSERT INTO events (type, payload, created_at) VALUES (?, ?, NOW())'); foreach ($events as $event) { $statement->execute([$event['type'], json_encode($event['data'], JSON_THROW_ON_ERROR)]); } ``` --- ## Redis — client setup ```php set('key', 'value'); $value = $redis->get('key'); // 'value' // With TTL (seconds) $redis->set('session:abc', $data, 3600); $redis->delete('key'); $exists = $redis->exists('key'); // false ``` --- ## Redis — hash operations ```php createHashMap('user:42'); $map->set('name', 'Alice'); $map->set('email', 'alice@example.com'); $name = $map->get('name'); // 'Alice' $all = $map->getAll(); // ['name' => 'Alice', 'email' => 'alice@example.com'] $count = $map->count(); // 2 $map->delete('email'); ``` --- ## Redis — pub/sub ```php subscribe('events'); foreach ($subscription as $message) { echo $message->channel . ': ' . $message->payload . "\n"; if ($message->payload === 'shutdown') { break; } } // Publisher (in a different fiber or file): $publisher->publish('events', json_encode(['type' => 'order.created', 'id' => 99], JSON_THROW_ON_ERROR)); ``` --- ## Redis — cache wrapper (RedisCache) ```php set('config', serialize($data), ttl: 3600); $value = $cache->get('config'); $cache->delete('config'); ``` --- ## Key Rules - **MySQL**: always use parameterized queries — never interpolate user data into SQL strings - **MySQL**: `MysqlConnectionPool` is thread-safe and reuses connections automatically; create it once - **Redis**: use `createRedisClient()` factory function, not `new RedisClient()` - **Redis**: each operation (get/set/subscribe) suspends the fiber and resumes when the server responds - **Transactions**: always call `rollback()` in the catch block before re-throwing - **Pub/sub**: the subscriber's `foreach` runs in a dedicated fiber — publish from a different fiber - Both MySQL pool and Redis client are process-local — do not share across worker processes