Kotchasan Framework Documentation
Kotchasan\Cache\QueryCache
Kotchasan\Cache\QueryCache
QueryCache เป็น cache wrapper เฉพาะสำหรับ database query caching โดยจะสร้าง cache keys จาก SQL queries และ parameters โดยอัตโนมัติ
สารบัญ
ภาพรวม
QueryCache มีคุณสมบัติดังนี้:
- Automatic Key Generation: สร้าง cache key จาก SQL + parameters
- Query Builder Integration: ทำงานร่วมกับ QueryBuilder ได้โดยตรง
- Enable/Disable: เปิด/ปิด caching ได้ตลอดเวลา
- Statistics: ติดตาม hits, misses, writes
- Table Invalidation: ล้าง cache เมื่อตารางถูกแก้ไข
เมื่อไหร่ควรใช้:
- ต้องการ cache ผลลัพธ์ของ database queries
- Queries ที่ซับซ้อนและใช้เวลาประมวลผล
- ข้อมูลที่ไม่เปลี่ยนแปลงบ่อย
การติดตั้งและใช้งาน
ความต้องการ
- PHP 7.4 หรือสูงกว่า
- Kotchasan Framework
- Cache implementation (FileCache, RedisCache, หรือ MemoryCache)
การใช้งานพื้นฐาน
use Kotchasan\Cache\QueryCache;
use Kotchasan\Cache\FileCache;
use Kotchasan\Database;
// สร้าง underlying cache
$fileCache = new FileCache(['path' => ROOT_PATH . 'datas/cache/']);
// สร้าง QueryCache
$queryCache = new QueryCache($fileCache, 3600);
// ใช้กับ Database
Database::setCache($fileCache, 3600);
// Queries จะถูก cache อัตโนมัติ
$db = Database::create();
$users = $db->select('*')
->from('users')
->where('status', '=', 'active')
->cache(true) // เปิด cache สำหรับ query นี้
->execute();เมธอดหลัก
__construct()
สร้าง QueryCache instance
Signature:
public function __construct(CacheInterface $cache, int $defaultTtl = 3600)Parameters:
$cache- Cache implementation (FileCache, RedisCache, etc.)$defaultTtl- TTL เริ่มต้น (วินาที)
get()
ดึง cached query result
Signature:
public function get(QueryBuilderInterface $query)Parameters:
$query- QueryBuilder instance
Returns: Cached result หรือ null ถ้าไม่พบ
set()
Cache query result
Signature:
public function set(QueryBuilderInterface $query, $result, ?int $ttl = null): boolParameters:
$query- QueryBuilder instance$result- ผลลัพธ์ที่จะ cache$ttl- TTL เป็นวินาที (optional)
generateKey()
สร้าง cache key จาก query
Signature:
protected function generateKey(QueryBuilderInterface $query): stringgetByKey() / setByKey()
ใช้ raw SQL แทน QueryBuilder
Signatures:
public function getByKey(string $sql, array $params = [])
public function setByKey(string $sql, array $params, $result, ?int $ttl = null): boolinvalidate()
ลบ cached query
Signature:
public function invalidate(QueryBuilderInterface $query): boolinvalidateTable()
ล้าง cache ทั้งหมดของตาราง
Signature:
public function invalidateTable(string $table): boolenable() / disable() / isEnabled()
เปิด/ปิด caching
Signatures:
public function enable(): self
public function disable(): self
public function isEnabled(): boolgetStats()
ดึงสถิติ
Signature:
public function getStats(): arrayReturns:
[
'hits' => 500,
'misses' => 100,
'writes' => 300,
'enabled' => true,
'default_ttl' => 3600,
'backend' => 'Kotchasan\\Cache\\FileCache',
'backend_stats' => [...] // สถิติของ underlying cache
]ตัวอย่างการใช้งาน
1. การ Cache Query พื้นฐาน
use Kotchasan\Cache\QueryCache;
use Kotchasan\Cache\FileCache;
use Kotchasan\Database;
// Setup
$fileCache = new FileCache(['path' => ROOT_PATH . 'datas/cache/']);
$queryCache = new QueryCache($fileCache, 3600);
$db = Database::create();
// สร้าง query
$query = $db->select('*')
->from('products')
->where('category', '=', 'electronics')
->orderBy('price');
// ตรวจสอบ cache ก่อน
$products = $queryCache->get($query);
if ($products === null) {
// ไม่มี cache, execute query
$products = $query->execute();
// Cache ผลลัพธ์
$queryCache->set($query, $products, 600);
}
// ใช้ข้อมูล
foreach ($products as $product) {
echo $product->name . "\n";
}2. การ Invalidate Cache เมื่อข้อมูลเปลี่ยน
use Kotchasan\Cache\QueryCache;
use Kotchasan\Cache\RedisCache;
use Kotchasan\Database;
class ProductRepository
{
private QueryCache $queryCache;
private Database $db;
public function __construct()
{
$redisCache = new RedisCache('localhost', 6379);
$this->queryCache = new QueryCache($redisCache, 600);
$this->db = Database::create();
}
public function findByCategory(string $category): array
{
$sql = "SELECT * FROM products WHERE category = ?";
$params = [$category];
// ลอง cache ก่อน
$result = $this->queryCache->getByKey($sql, $params);
if ($result !== null) {
return $result;
}
// Query จาก database
$result = $this->db->select('*')
->from('products')
->where('category', '=', $category)
->execute();
// Cache
$this->queryCache->setByKey($sql, $params, $result);
return $result;
}
public function update(int $id, array $data): bool
{
$result = $this->db->update('products')
->set($data)
->where('id', '=', $id)
->execute();
if ($result) {
// ล้าง cache ที่เกี่ยวข้อง
$this->queryCache->invalidateTable('products');
}
return $result;
}
}3. การเปิด/ปิด Cache ตามสถานการณ์
use Kotchasan\Cache\QueryCache;
use Kotchasan\Cache\MemoryCache;
$queryCache = new QueryCache(new MemoryCache(), 600);
// ปิด cache ระหว่าง development หรือ debugging
if (defined('DEBUG') && DEBUG) {
$queryCache->disable();
}
// หรือปิดชั่วคราวสำหรับ queries ที่ต้องการข้อมูลล่าสุด
$queryCache->disable();
$realTimeData = $db->select('*')
->from('live_stats')
->execute();
$queryCache->enable();4. การดูสถิติ Cache
$db = Database::create();
// Execute queries...
for ($i = 0; $i < 100; $i++) {
$users = $db->select('*')
->from('users')
->where('id', '=', $i % 10)
->cache(true, 60)
->execute();
}
// ดูสถิติ
$queryCache = Database::getQueryCache();
$stats = $queryCache->getStats();
echo "Cache Performance:\n";
echo "- Hits: {$stats['hits']}\n";
echo "- Misses: {$stats['misses']}\n";
echo "- Hit Rate: " . round($stats['hits'] / ($stats['hits'] + $stats['misses']) * 100, 2) . "%\n";5. การใช้กับ Kotchasan\Database โดยตรง
use Kotchasan\Database;
use Kotchasan\Cache\CacheFactory;
// กำหนดค่า cache ให้ Database
Database::configureCache([
'driver' => 'file',
'path' => ROOT_PATH . 'datas/cache/'
], 3600);
$db = Database::create();
// Query พร้อม cache
$users = $db->select('*')
->from('users')
->where('status', '=', 'active')
->cache(true, 600) // cache 10 นาที
->execute();
// Query ที่สอง (ถ้า parameters เหมือนกัน จะได้จาก cache)
$users = $db->select('*')
->from('users')
->where('status', '=', 'active')
->cache(true, 600)
->execute(); // จาก cache!Best Practices
1. ใช้ TTL ที่เหมาะสมกับข้อมูล
// ข้อมูลที่ไม่ค่อยเปลี่ยน - TTL ยาว
$queryCache->set($categoryQuery, $categories, 86400); // 24 ชั่วโมง
// ข้อมูลที่เปลี่ยนบ่อย - TTL สั้น
$queryCache->set($orderQuery, $orders, 60); // 1 นาที
// ข้อมูล real-time - ไม่ cache
$queryCache->disable();2. Invalidate Cache อย่างถูกต้อง
// เมื่อ INSERT/UPDATE/DELETE ควร invalidate cache ที่เกี่ยวข้อง
function updateUser($id, $data)
{
$db->update('users')->set($data)->where('id', '=', $id)->execute();
// Invalidate cache
$queryCache->invalidateTable('users');
}3. ใช้ Cache Backend ที่เหมาะสม
// Development: MemoryCache
$cache = new MemoryCache();
// Single server: FileCache
$cache = new FileCache(['path' => '/tmp/cache/']);
// Multiple servers: RedisCache
$cache = new RedisCache('redis.example.com', 6379);ข้อควรระวัง
⚠️ Warning:
- อย่า cache queries ที่มีข้อมูลที่เปลี่ยนบ่อย
- อย่าลืม invalidate cache เมื่อข้อมูลถูกแก้ไข
- ระวัง stale data
💡 Tip: ใช้ short TTL สำหรับข้อมูลที่เปลี่ยนบ่อย และ long TTL สำหรับ static data
คลาสที่เกี่ยวข้อง
- CacheFactory - สร้าง cache instances
- [FileCache] - Cache แบบไฟล์
- MemoryCache - Memory Cache
- RedisCache - Redis Cache
- Database - คลาสหลักสำหรับฐานข้อมูล