2

i made this function: /* MEMCACHE */

function cache_query($sql,$nombre,$tiempo = -1){
    $cache = new Memcache();
    $cache->pconnect('localhost',11211);
    $query_cacheada = $cache->get($nombre);
    if ( $query_cacheada  === false ) {
             /* key not in memcache, perfom query, cache it and return */
         $res = mysql_query($sql);
         $cache->set($nombre,$res, 0, 60*60*24);  
         return $res; /* this looks good */
    }else{
             /* key in memcache, just return cached  */
         return $query_cacheada;  /* this doesnt return right elements */
    }
}

wich i am using so:

class text{

    protected $id;
    protected $key;
    protected $language;
    protected $text;

    function __construct($clave,$lan){
       $consulta = cache_query("SELECT * FROM textos  
                                WHERE clave = '$clave' AND lengua = '$lan'" ,"TRANSLATION_".$clave."_".$lan);


        if(mysql_num_rows($consulta)>0){
            while($item = mysql_fetch_array($consulta)){
                $this->id = $item['id'];
                $this->clave = $item['key'];
                $this->lengua = $item['language'];
                $this->texto = $item['text'];

            }
                return true;
         }
    }
    function get_text(){
          return $this->text;
    }
}
function translation($key,$language){
     $tem = new text($key,$language);
     return $tem->get_text();
}

then:

$translationText = translation('hello','fr');

The problem is that it stores in cache arrays (always zero), var_dump($m->get(k)) returns:

int(0) int(0) int(0) int(0) int(0) int(0) int(0) int(0) int(0) int(0) int(0) .....

And the $sql query is fine because the rows are collected fine and printed fine, the problem is with the stored value..

I have cleared the cache doing (several times, to make sure the values are not from a previous wrong output):

$consulta = $cache->get($nombre);
             /* manually*/
             $consulta = false;
        if ( $consulta === false) {
            $consulta = mysql_query($sql);
            $cache->set($nombre,$consulta, MEMCACHE_COMPRESSED, 60*60*24);
        };

so.. what am I missing?

EDIT

Here is a codepad, the problem is the mysql_query and memecache is not enabled, but in case someone wants to fiddle with it a bit

http://codepad.viper-7.com/PJNepH

Toni Michel Caubet
  • 19,333
  • 56
  • 202
  • 378
  • Is it ok that you pass `$sql` but use `$query`, and pass `$tiempo` but use `$iempo`? – zerkms May 26 '12 at 21:54
  • yep. You want to know what's **actually** in that variable, don't you? – zerkms May 26 '12 at 22:07
  • hey! finnaly I got to see var_dump: boolean(false) so it's not finidng it. also edited the function a bit @zerkms – Toni Michel Caubet May 27 '12 at 20:28
  • Why are you trying to use memcache at all, when the [MySQL query cache](http://dev.mysql.com/doc/en/query-cache.html) should do a perfectly good job of this completely transparently to your application? – eggyal May 29 '12 at 00:45
  • @eggyal too much mysql load.. i know it's not the right fix but it would buy me some time.. I would like to know how to do this anyway :) – Toni Michel Caubet May 29 '12 at 06:56

3 Answers3

3

You can only cache something that can be serialized. This includes everything but the type resource (which is returned from a successful mysql_query). You need to change your logic a bit so that you are caching an array. Change this:

$res = mysql_query($sql);
$cache->set($nombre,$res, 0, 60*60*24); 

To:

$res = mysql_query($sql);
$rows = array();
while($row = mysql_fetch_array($res)) $rows[] = $row;
$cache->set($nombre, $rows, 0, 60*60*24); 

Then change this:

if(mysql_num_rows($consulta)>0){
    while($item = mysql_fetch_array($consulta)){
        $this->id = $item['id'];
        $this->clave = $item['key'];
        $this->lengua = $item['language'];
        $this->texto = $item['text'];

    }
    return true;
}

To:

foreach($consulta as $item){
       $this->id = $item['id'];
       $this->clave = $item['key'];
       $this->lengua = $item['language'];
       $this->texto = $item['text'];
}

// This is your old code written to work with a 2D array instead of a resource,
// But this keeps overwriting the same variables in a loop,
// if you selected multiple rows; otherwise you don't even need a loop and can just do:

$this->id = $consulta[0]['id'];
$this->clave = $consulta[0]['key'];
$this->lengua = $consulta[0]['language'];
$this->texto = $consulta[0]['text'];
Paul
  • 139,544
  • 27
  • 275
  • 264
1

The important thing to note is that you cannot store a result resource returned from mysql_query. I would recommend looping through the result set, fetching them with mysql_fetch_array, and then storing those objects in the cache.

Edit As PaulP.R.O. pointed out, the explicit serialize/deserialize were redundant.

$result = mysql_query($sql) or die("Query failed");

$results = array();

while ($array = mysql_fetch_array($result))
{
    $results[] = $array;
}

$cache->set($nombre, $results, MEMCACHE_COMPRESSED, 60*60*24);

When retrieving from memcached, simply use the unserialized array.

$cachedItem = $cache->get($nombre);

if ($cachedItem !== false) {
    var_dump($cachedItem);
}
Matt Beckman
  • 5,022
  • 4
  • 29
  • 42
  • 1
    It's pointless to call serialize and unserialize, memcache will already do that automatically for objects or arrays. – Paul May 29 '12 at 03:48
  • hi! thanks for your answer but this while with mysq_fetch_object wont generate the same array than mysql_result so the values are not printed well and of corse not stored well... any idea why? (i am returning $results because $result has been emptyed in the loop) – Toni Michel Caubet May 29 '12 at 07:13
  • @ToniMichelCaubet You can't store what is returned from mysql_query. You can only store what is returned from functions that use the result resource returned from mysql_query (e.g. `mysql_fetch_object` or `mysql_fetch_array`). @PaulP.R.O You're right. I'll remove the explicit serialize/deserialize functions. – Matt Beckman May 29 '12 at 21:33
  • Paul also rewrote some of your code, so it might be worth it to simply try his code changes out, if our reasons for not storing a result resource aren't clear. – Matt Beckman May 29 '12 at 21:41
0

Memcache doesn't accept TTLs longer than 30 days. You can also use a ttl of 0 to set the key to never expire OR you set a ttl of less than 30 days.

eliminating memcached's 30-day limit

To create an easily serializable variable, you can do something like this.

$consulta = mysql_query($sql);   
while ($row = mysql_fetch_assoc($consulta)) {
  $data[] = $row;
}
$cache->set($nombre,$data, MEMCACHE_COMPRESSED, 60*60*24);
Community
  • 1
  • 1
Chris Henry
  • 11,914
  • 3
  • 30
  • 31
  • Edited function, now it returns values! but for some reason, it stores the mysql result, and var_dump returns: int(0) int(0) int(0) int(0) int(0) int(0).... any idea? (before being cached they where displayed as expected, so the mysql query is fine) – Toni Michel Caubet May 27 '12 at 21:10
  • Seems like it's serializing the mysql resource. Typically, what you'd want to do is format your data into a more easily serializable format, like a PHP array, or even JSON, then pass that to $cache->set. – Chris Henry May 27 '12 at 21:12
  • I see your edit. this returns the same that cache wa s storing... don't you have to initialise $data? i think the problem is that my query returns an array of objects... – Toni Michel Caubet May 27 '12 at 21:36
  • From a syntax standpoint, you actually don't have to initialize $data in this case. As this is just example code, I didn't deem it necessary. However, you should initialise it, as you will get a PHP notice in the `$cache->set` line if you do not. Have you cleared cache? – Chris Henry May 27 '12 at 21:52
  • what i mean is that this mysql_query is something like 'select * from users where id=5'), so it doesnt contain an array of values but objects. is that ok the way i am doing it? – Toni Michel Caubet May 27 '12 at 22:01
  • Actually, `mysql_result` will return an object of type resource, and then you need to use `mysql_fetch_assoc` or something like it to change it into simple php arrays. So yes, if you follow the example, the way you're doing that is fine. – Chris Henry May 27 '12 at 22:06