You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
4.8 KiB

<?php
require_once __DIR__ . '/Config.php';
class Database {
private static $instance = null;
private $config;
private $connections = [];
private $inUse = [];
private $maxConnections = 10;
private $minConnections = 3;
private function __construct() {
$this->config = Config::getInstance();
$this->maxConnections = $this->config->get('database.max_connections', 10);
$this->minConnections = $this->config->get('database.min_connections', 3);
$this->initPool();
}
public static function getInstance() {
if (self::$instance === null) { self::$instance = new self(); }
return self::$instance;
}
private function initPool() {
for ($i = 0; $i < $this->minConnections; $i++) { $this->connections[] = $this->createConnection(); }
}
private function createConnection() {
$dbConfig = $this->config->get('database');
$host = $dbConfig['host'];
$port = $dbConfig['port'];
$database = $dbConfig['database'];
$username = $dbConfig['username'];
$password = $dbConfig['password'];
$charset = $dbConfig['charset'];
$dsn = "mysql:host={$host};port={$port};charset={$charset}";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_PERSISTENT => true
];
$pdo = new PDO($dsn, $username, $password, $options);
$pdo->exec("CREATE DATABASE IF NOT EXISTS `$database` CHARACTER SET $charset COLLATE {$dbConfig['collation']}");
$pdo->exec("USE `$database`");
return $pdo;
}
private function getConnection() {
if (count($this->connections) > 0) {
$pdo = array_pop($this->connections);
if (!$this->isValid($pdo)) { $pdo = $this->createConnection(); }
$this->inUse[] = $pdo;
return $pdo;
}
if (count($this->inUse) < $this->maxConnections) {
$pdo = $this->createConnection();
$this->inUse[] = $pdo;
return $pdo;
}
usleep(1000);
return $this->getConnection();
}
private function release($pdo) {
$key = array_search($pdo, $this->inUse);
if ($key !== false) {
unset($this->inUse[$key]);
if ($this->isValid($pdo)) { $this->connections[] = $pdo; }
}
}
private function isValid($pdo) {
try { $pdo->query("SELECT 1"); return true; } catch (PDOException $e) { return false; }
}
public function fetchAll($sql, $params = []) {
$pdo = $this->getConnection();
try { $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchAll(); }
finally { $this->release($pdo); }
}
public function fetchOne($sql, $params = []) {
$pdo = $this->getConnection();
try { $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetch(); }
finally { $this->release($pdo); }
}
public function query($sql, $params = []) {
$pdo = $this->getConnection();
try { $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt; }
finally { $this->release($pdo); }
}
public function insert($sql, $params = []) {
$pdo = $this->getConnection();
try { $stmt = $pdo->prepare($sql); $stmt->execute($params); return $pdo->lastInsertId(); }
finally { $this->release($pdo); }
}
public function update($sql, $params = []) {
$pdo = $this->getConnection();
try { $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->rowCount(); }
finally { $this->release($pdo); }
}
public function delete($sql, $params = []) {
$pdo = $this->getConnection();
try { $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->rowCount(); }
finally { $this->release($pdo); }
}
public function beginTransaction() { $pdo = $this->getConnection(); $pdo->beginTransaction(); return $pdo; }
public function commit($pdo = null) { if ($pdo) { $pdo->commit(); $this->release($pdo); } }
public function rollback($pdo = null) { if ($pdo) { $pdo->rollBack(); $this->release($pdo); } }
public function isConnected() {
$pdo = $this->getConnection();
try { $pdo->query("SELECT 1"); return true; }
catch (PDOException $e) { return false; }
finally { $this->release($pdo); }
}
public function getPoolStatus() {
return [
'total_connections' => count($this->connections) + count($this->inUse),
'available_connections' => count($this->connections),
'in_use_connections' => count($this->inUse),
'max_connections' => $this->maxConnections
];
}
}