我有很多图像进入mysql数据库,这些图像被绘制成:<img src="/PrintImage.php?$id&width&height&quality" />
。
问题是,对于每个图像,我通过类调用数据库。为了更好地解释它,这里是代码:
已编辑:完全发布课程代码
HTML视图(示例):
<img src="/PrintImage.php?id=10&width=120&height=120&quality=100" />
<img src="/PrintImage.php?id=20&width=120&height=120&quality=100" />
PrintImage.php
<?php
include_once($_SERVER['DOCUMENT_ROOT'].'/php/classes/Galerias.php');
$a = new \Galerias();
$i = $_GET['i'];
$w = $_GET['w'];
$h = $_GET['h'];
$q = $_GET['q'];
$a->Pintar($i, $w, $h, $q);
unset($a);
Gallery.php :
<?php
namespace Galerias;
include_once 'Database.php';
include_once 'Utils.php';
use \Database;
use \Utils;
class Galerias {
private $img_max_width = 1024;
private $img_max_height = 768;
private $img_quality = 85;
function __construct(){
$this->Database = new Database();
$this->Utils = new Utils();
}
public function Pintar($id, $width, $height, $quality){
$query = "select (select titulo from imagenes where id=$id) as titulo, (select imagen from imagenes where id=$id) as imagen";
$data = $this->Database->GetData($query);
$titulo = $data[0]['titulo'];
$tmp = $data[0]['imagen'];
$dataimg = $this->Utils->formatImage("string", $tmp, $width, $height, false);
$mime = $dataimg[1];
header("Content-type: $mime");
header("Content-Disposition: inline; filename=$titulo");
imagejpeg($dataimg[0], null, $quality);
}
}
database.php中:
<?php
namespace Database;
include_once 'Utils.php';
use \Utils;
class Database {
private $host = "localhost";
private $user = "user";
private $pass = "pass";
private $daba = "database";
private $link;
public $Utils;
function __construct(){
$this->Open();
$this->Utils = new Utils();
}
function __destruct(){
error_log('Database destruct');
}
private function Open(){
$this->link = mysql_connect($this->host, $this->user, $this->pass);
error_log('open succeeded');
mysql_select_db($this->daba, $this->link) or $this->Utils->newEx("Class Database->Open(): ".mysql_error());
}
private function Close(){
mysql_close($this->link) or $this->Utils->newEx("Class Database->Close(): ".mysql_error());
error_log('close succeeded');
}
public function GetData($query){
$data = array();
$query = mysql_query($query) or $this->Utils->newEx("Class Database->GetData(): ".mysql_error(), true);
while( $result = mysql_fetch_array($query) ){
$data[] = $result;
}
$this->FreeResults($query);
return $data;
}
public function InsertData($query){
if( !mysql_query($query) ){
$this->Utils->newEx("Class Database->InsertData(): ". mysql_error(), true);
return false;
}
return true;
}
public function DeleteData($query){
if( !mysql_query($query) ){
$this->Utils->newEx("Class Database->DeleteData(): ". mysql_error(), true);
return false;
}
return true;
}
public function FreeResults($res = null){
if( !is_null($res) ) mysql_free_result($res);
}
}
我正在多次调用数据库,因为每个图库需要加载~50 / 100个图像。 问题是,我该如何有效地完成这项任务?提前致谢
答案 0 :(得分:2)
您真正的问题是:如何最大限度地减少对数据库的调用量。
数据存储在数据库中,因此必须进行调用以检索数据。但是你需要问自己,我真的每次都需要问这个问题吗?
在当前对象模型中,仅在创建对象时检索每张图片的唯一数据。每次您想要阅读信息时,这将添加一个电话。这是一个非常常见的错误,并且(正如您已经意识到的那样)根本无法扩展。
您需要的是在调用之前使对象已拥有数据。有很多方法可以做到这一点。只要有活跃的开发人员,对象工厂,缓存对象,内存缓存,redis列表就可以了。 我邀请你试着在盒子外思考并找到解决方案。因为如果您了解问题并解决问题,您将更好地掌握对象模型和陷阱。
让我们再拿一遍,你确定你需要在构造对象时进行数据库调用吗?如果您知道所需数据的子集,则应批量询问。这将删除对数据库的大量查询。
也许Galerias
可以在一次抓取大量Pintar
的情况下发挥作用?
我知道这不是“做这个”的答案,可能会被投票。但至少尝试:)。
另外:永远不要直接使用查询参数$ _GET $ _POST而不先清理它们!
答案 1 :(得分:1)
最后,我得到了逻辑系统来减少 - 相当于 - 对数据库的调用量。之前,我使用PHP文件作为图像src
直接从数据库打印图像(带有标题等)。这是一个可怕的失败。要解决的问题是:
我需要使用PHP文件作为图像src,传递ID,宽度,高度和质量。当然,它必须是一个友好的uri。所以我不能使用base64编码来打印图像。它必须是一个PHP文件(其他文件,其他进程,它没有连接到第一个文件)。
我使用的是共享主机,加载像memcache这样的扩展程序的想法是不可行的。
问题2告诉我,我无法在任何地方保存图像(或其他数据)以便在网站上使用。 (这是错的)。
我所做的(在思考,搜索和思考之后......)是使用$_SESSION
存储,以前序列化所有图像。所以,我解决了所有问题。现在,必须寻找一个有效的逻辑来填充代码。结果如下:
// Session Cache Class (static)
namespace SessionCache;
ini_set('memory_limit', '256M'); // this is the best issue of this system
session_start();
class SessionCache {
// todo: add the possible to expire the session
private static $SessionName = 'SessionCache';
public static function Check($name){
if( empty($_SESSION[self::$SessionName]) ) return false;
if( empty($_SESSION[self::$SessionName][$name]) ) return false;
else return true;
}
public static function Set($name, $data){
if( self::Check($name) ) return;
$data = serialize($data);
$_SESSION[self::$SessionName][$name] = $data;
}
public static function Get($name){
if( self::Check($name) ){
$data = unserialize($_SESSION[self::$SessionName][$name]);
return $data;
}
else return null;
}
public static function Flush($name){
if( self::Check($name) ) unset($_SESSION[self::$SessionName][$name]);
}
public static function Destroy(){
session_destroy();
}
}
现在,(当前)逻辑:
// Images Class. Here I use some extra stuff. Feel free to read the comments
namespace AdminPanel;
include_once 'SessionCache.php';
include_once 'Database.php';
include_once 'Utils.php';
use \AdminPanel\Database;
use \AdminPanel\Utils;
use SessionCache\SessionCache;
use stdClass;
class Patrocinios {
private $cache_name = 'Patrocinadores';
private $img_width = 225;
private $img_height = 70;
private $img_quality = 100;
public function __construct(){
$this->Database = new \AdminPanel\Database();
$this->Utils = new \AdminPanel\Utils();
}
private function CreateImageCache(){
if( SessionCache::Check($this->cache_name) ) return null;
$query = "select * from patrocinadores";
$this->Database->Open();
$data = $this->Database->GetData($query);
$this->Database->Close();
$patros = new stdClass();
if( count($data) > 0 ){
for( $i=0; $i<count($data); $i++ ){
$id = $data[$i]['id'];
$nombre = $data[$i]['nombre'];
$uri = $data[$i]['web'];
$mimetype = $data[$i]['tipo'];
$imagedata = $data[$i]['imagen'];
$patros->patro[$id] = new stdClass();
$patros->patro[$id]->id = $id;
$patros->patro[$id]->nombre = $nombre;
$patros->patro[$id]->uri = $uri;
$patros->patro[$id]->mimetype = $mimetype;
$patros->patro[$id]->data = $imagedata; // the image BLOB
}
}
SessionCache::Set($this->cache_name, $patros);
}
public function GetPatrocinadores(){ // this method is the only one called from the main view
$this->CreateImageCache();
$patros = SessionCache::Get($this->cache_name);
return $patros;
}
public function Pintar($id, $width, $height, $quality){ // this method is called from the PHP file used to print the images
if( !SessionCache::Check($this->cache_name) ) $patros = $this->GetPatrocinadores();
else $patros = SessionCache::Get($this->cache_name);
$dataimg = $this->Utils->formatImage("string", $patros->patro[$id]->data, $width, $height); // creates new image with desired measures and quality
header('Content-Type: '.$patros->patro[$id]->mimetype);
header('Content-Length: '.strlen($patros->patro[$id]->data));
imagejpeg($dataimg[0], null, $quality);
}
}
我只有一个带有会话对象名称的变量($cache_name
)。首先,我检查是否存在(来自之前的通话)。如果没有,我使用数据库中的信息填充stdClass()
对象并将其存储在会话中。
<ul id="ulPatrocinadores">
<?php
include_once $_SERVER['DOCUMENT_ROOT'].'/php/classes/Patrocinios.php';
$p = new \AdminPanel\Patrocinios();
$patros = $p->GetPatrocinadores();
$str = '';
foreach( $patros as $value ){
foreach( $value as $patro ){
$id = $patro->id;
$nombre = str_replace(" ", "_", $patro->nombre);
$web = $patro->uri;
$str .= '<li>';
$str .= '<a href="'.$web.'" title="'.$nombre.'" target="_blank"><img src="/'.$nombre.'_pat-i='.$id.'&w=225&h=70&q=85" alt="'.$nombre.'" /></a>';
}
}
echo $str;
?>
</ul>
以上是打印图像的主视图。请注意,锚点和图像源转到调用方法Pintar()
的PHP文件。我使用RewriteRule
重定向它。
<?php
include_once '../scripts/PrintPartner.php';
$a = new \AdminPanel\Patrocinios();
$i = $_GET['i'];
$w = $_GET['w'];
$h = $_GET['h'];
$q = $_GET['q'];
$a->Pintar($i, $w, $h, $q);
unset($a);
所以,我终于实现了它。我不知道这是否是一个好的系统,因为$_SESSION
与php memory_limit
有关系,但经过两天的思考,我无法获得更好的东西。
我取得的成就:
之前:对数据库的每个图像进行一次查询。现在:对一个会话(或我需要的时间)的所有图像进行一次查询。
保持友好的uris,根据需要动态创建图像文件,仍然使用PHP文件作为图像src
。
使用共享主机减少对数据库的调用的良好系统。
希望这种体验有助于某人。