Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu mysql Kanał ATOM (tag: mysql)

Autor wpisu: Tomasz Kowalczyk, dodany: 01.07.2011 00:22, tagi: sql, mysql

Oprogramowanie komputera zawiera w sobie wiele pułapek, o których trzeba wiedzieć, żeby w nie nie wpaść. Szczęśliwym trafem jeszcze nie miałem okazji cierpieć przez opisywany dzisiaj problem - przeczytałem o nim podczas poszukiwania informacji na temat innego, który już opisałem na niniejszym blogu. Serwer SQL, a dokładnie MySQL, to jedno z najpopularniejszych rozwiązań tej klasy, [...]

Autor wpisu: Diabl0, dodany: 29.06.2011 15:37, tagi: mysql, php, sql, zend_framework

Od jakiegoś czasu borykałem się z problemem dlaczego czasami zapisywane do bazy danych zserializowane dane są „obcinane. Poszukiwania, googlanie niewiele pomagało aż a końcu trafiłem gdzieś na informację że problemem może być znak NULL (0×00) w którym PHPowe serialize się lubuje :) . A koro tak, to postanowiłem napisać swoją wersję serialize.

Kod tutaj:

<?php
/**
 * Serializowanie i deserializowanie treści zawierających 0x00
 *
 * @category    Mao
 * @package     Mao_Serializer
 * @author      Krzysztof 'Diabl0' Szatanik
 * @copyright   Copyright (c) 2011, MAO Group
 * @version     $Id: Form.php 1164 2009-11-10 13:01:53Z diabl0 $
 */

/**
 * Własna nakładka na serializację
 *
 */
class Mao_Serializer {

	const CHAR_0x00 = '\\$0x00$/';

	/**
	 * Serializuje obiekt jak serialize() z tym że zastępuje znak 0x00
	 * aby nie sprawiał problemu przy zapisie do bazy danych
	 *
	 *
	 * @param mixed $obj
	 *
	 * @return string
	 */
	static function serialize( $obj ) {
		return str_replace( chr(0x00), self::CHAR_0x00, serialize( $obj ) );
	}

	/**
	 *
	 * Deserializuje obiekt jak unserialize() z tym że przywraca
	 * zastąpiony znak 0x00
	 *
	 * @param string $string
	 *
	 * @return mixed
	 */
	static function unserialize( $string ) {
		return unserialize( str_replace( self::CHAR_0x00, chr(0x00), $string ) );
	}

}

Użycie jest banalne:

<?php
$text = 'to jest test znaku [' . chr(0) . '] - czy sie dobrze zapisuje do bazy';
$serialized = Mao_Serializer::serialize($text);
$unserialized = Mao_Serializer::unserialize($serialized);
?>

Wiem że nie jest to idealne rozwiązanie ale na razie nie mam czasu aby przysiąść i dorobić jakąś konwersję w locie na poziomie Zend_Db_Adapter

Autor wpisu: Tomasz Kowalczyk, dodany: 19.06.2011 16:04, tagi: javascript, jquery, mysql, php

Chcąc stworzyć dynamiczną stronę oferującą wiele funkcjonalności w sposób zbliżony do tego, jak zachowują się aplikacje desktopowe, niestety nie mamy innej możliwości niż wykorzystanie technologii AJAX. Wychodząc naprzeciw tym wymaganiom dzisiaj publikuję kolejny zestaw przydatnych materiałów dotyczących tworzenia różnego rodzaju funkcjonalności z jej wykorzystaniem. Mam nadzieję, że przydadzą się Wam zarówno w pracy, jak i [...]

Autor wpisu: singles, dodany: 10.05.2011 19:45, tagi: mysql

MySQL i porównywanie ciagów z zachowaniem wielkości znaków

Zdarza się, że podczas programowania aplikacji internetowej opartej na MySQL potrzebujemy porównania z zachowaniem wielkości znaków, gdyż domyślnie porównanie wykonane jest bez zwracania uwagi an wielkość liter. Wpis ten przybliży metody, w jaki sposób można tą funkcjonalność osiągnąć.

Wprowadzenie

Zachowanie takie wynika z tego, że ogromna większość tworzonych tabel posiada ustawiony tryb porównania z końcówką ci – co znaczy nie mniej nie więcej case insensitive. Kiedy wylistujemy dostępne typy porównań za pomocą polecenia SHOW COLLATION;, otrzymamy listę bez przyrostków cs, czyli case sensitive. MySQL udostępnia kilka porównań tego typu. Wpisanie polecenia:

SHOW COLLATION LIKE '%_cs';

zwróci następujące rekordy:

+--------------------+---------+----+---------+----------+---------+
| Collation          | Charset | Id | Default | Compiled | Sortlen |
+--------------------+---------+----+---------+----------+---------+
| latin1_general_cs  | latin1  | 49 |         | Yes      |       1 |
| latin2_czech_cs    | latin2  |  2 |         | Yes      |       4 |
| cp1250_czech_cs    | cp1250  | 34 |         | Yes      |       2 |
| latin7_estonian_cs | latin7  | 20 |         | Yes      |       1 |
| latin7_general_cs  | latin7  | 42 |         | Yes      |       1 |
| cp1251_general_cs  | cp1251  | 52 |         | Yes      |       1 |
+--------------------+---------+----+---------+----------+---------+
6 rows in set (0,00 sec)

Jak widać, nie ma tutaj żadnego typu, którego moglibyśmy użyć w polskojęzycznych aplikacjach. Dlatego musimy sobie poradzić inaczej – poniżej przedstawiam kilka sposobów.

Użyjemy prostej tabeli:

CREATE TABLE demo (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(100) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Do tabeli dodane zostały dwa rekordy:

mysql> select * from demo;
+----+------+
| id | name |
+----+------+
|  1 | Foo  |
|  2 | FOO  |
|  3 | Bar  |
+----+------+
3 rows in set (0,00 sec)

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Tomasz Kowalczyk, dodany: 08.05.2011 19:40, tagi: php, mysql, framework, symfony2

Ze wszystkich języków programowania, jakich tematykę poruszam / poruszałem na tym blogu, PHP zajmuje zaszczytne, pierwsze miejsce pod względem liczby wpisów. Zastanawiający jest zatem fakt, że w Linkdumpie jest go relatywnie najmniej. W ramach poprawy tej statystyki zapraszam do zapoznania się z listą dziesięciu wyselekcjonowanych linków o PHP właśnie. Fotografia: totalAdo, CC-BY. Linkdump: Chłopcy PeHaPowcy. [...]

Autor wpisu: Śpiechu, dodany: 07.05.2011 12:56, tagi: php, mysql

Dzisiaj kończę temat wstrzykiwania zależności. Punktem wyjścia będzie poprzedni kod. Kontener posłuży do skonfigurowania jeszcze dwóch obiektów. Napisałem sobie 2 proste klasy: SelectQuery, który odpyta bazę danych na podane zapytanie oraz SelectQueryCache, który zachowa wynik zapytania do pliku. Wynik będzie ważny tylko przez podany czas.

Przy okazji zmieniłem trochę formatowanie składni na bardziej „Zend-Frameworkowe”. Mam nadzieję, że bardziej czytelne. Kolejną zmianą jest używanie w nazwach klas/zmiennych wyłączenie języka angielskiego. Wam to nie będzie przeszkadzać, a mnie oszczędzi masę czasu gdybym chciał coś kiedyś rzucić na szerokie wody.

W metodzie loadDefaults() dorzucamy zmienne konfigurujące obiekt cachujący i dwa domknięcia potrafiące wyprodukować gotowe obiekty:

//zmienne konfigurujące pdo z poprzedniego wpisu
 
$this->cache_filename = 'queries.cache';
$this->cache_interval = 30;
$this->cache_class = 'SelectQueryCache';
 
$this->selectQueryCache = function (DBKontener $k)
{
  return new $k->cache_class($k->cache_filename , k->cache_interval);
};
 
$this->selectQuery = function (DBKontener $k)
{
  $q = new SelectQuery($k->pdo_getPDO);
  // wstrzykujemy zaleznosc
  $q->setCache($k->selectQueryCache);
  return $q;
};

Właściwie to wpis można by teraz zamknąć. Widać jak cache tworzony jest na podstawie zmiennych oraz widać wstrzyknięcie zależności w postaci metody setCache(). Innym sposobem wstrzykiwania jest konstruktor. Nie zrobiłem tak z uwagi na to, że SelectQuery może sobie radzić bez obiektu cachującego, więc po co wymuszać.

Poniżej załączam kod dwóch wspomnianych wyżej klas.

class SelectQuery
{
  /**
   * @var PDO
   */
  protected $pdo;
 
  /**
   * @var SelectQueryCache 
   */
  protected $cache = null;
 
  public function __construct(PDO $pdo)
  {
    $this->pdo = $pdo;
  }
 
  /**
   * @param SelectQueryCache $sqc dependency injection
   */
  public function setCache(SelectQueryCache $sqc)
  {
    $this->cache = $sqc;
  }
 
  /**
   * @param string $query
   * @return array
   */
  public function getResults($query)
  {
    if ($this->cache)
    {
      $cachedResults = $this->cache->getCachedResults($query);
      if ($cachedResults !== null)
      {
        return $cachedResults;
      }
    }
    $q = $this->pdo->prepare($query);
    $q->execute();
    $rows = array();
    while ($row = $q->fetch(PDO::FETCH_ASSOC))
    {
      $rows[] = $row;
    }
    if ($this->cache)
    {
      $this->cache->cacheQuery($query , $rows);
    }
    return $rows;
  }
}
 
class SelectQueryCache
{
  /**
   * @var array contains all cached queries
   */
  protected $cachedQueries = array();
 
  /**
   * @var SPLFileInfo
   */
  protected $cacheFile;
 
  /**
   * @var int time interval in secs to check if cache is still valid
   */
  protected $validTime;
 
  public function __construct($filename , $validtime = 60)
  {
    $this->cacheFile = new SplFileInfo(__DIR__ . '/' . $filename);
    $this->validTime = (int) $validtime;
    $this->loadCache();
  }
 
  protected function loadCache()
  {
    if (!file_exists($this->cacheFile))
    {
      touch($this->cacheFile);
    }
    $file = $this->cacheFile->openFile('r');
    if ($file->flock(LOCK_SH))
    {
      $this->cachedQueries = json_decode(file_get_contents($file) , true);
      $file->flock(LOCK_UN);
    }
    else
    {
      throw new Exception('Cannot acquire file lock to read file');
    }
  }
 
  public function cacheQuery($query , $result)
  {
    $this->cachedQueries[$query] = array(
      'time' => time() ,
      'result' => $result);
  }
 
  public function getCachedResults($query)
  {
    if ($this->isValidCache($query))
    {
      return $this->cachedQueries[$query]['result'];
    }
    else
    {
      return null;
    }
  }
 
  protected function isValidCache($query)
  {
    if ($this->cachedQueries !== null
      && array_key_exists($query , $this->cachedQueries)
      && $this->isValidTime($this->cachedQueries[$query]['time']))
    {
      return true;
    }
    else
    {
      return false;
    }
  }
 
  protected function isValidTime($timestamp)
  {
    return ((time() - $this->validTime) < $timestamp);
  }
 
  protected function cleanUpOldCache()
  {
    foreach ($this->cachedQueries as $key => $cq)
    {
      if (!$this->isValidTime($cq['time']))
      {
        unset($this->cachedQueries[$key]);
      }
    }
  }
 
  protected function save()
  {
    $serializedData = json_encode($this->cachedQueries);
    $file = $this->cacheFile->openFile('w');
    if ($file->flock(LOCK_EX))
    {
      $file->fwrite($serializedData);
      $file->flock(LOCK_UN);
    }
    else
    {
      throw new Exception('Cannot acquire exclusive file lock to save file');
    }
  }
 
  public function __destruct()
  {
    $this->cleanUpOldCache();
    $this->save();
  }
}

Myślę, że w SelectQuery nie ma nic specjalnego, no może poza getResults(), które najpierw sprawdza czy jest cache i jakiś wynik, a jak nie to odpytuje bazę danych i zapisuje wynik do cache.

Za to w SelectQueryCache znajdzie się trochę mięska:

  1. Do serializacji danych używam json_encode, które jest ponoć trochę szybsze od zwykłej serializacji, a zapisane dane mają formę strawniejszą dla humanoidów.
  2. Dane w pliku trzymam w postaci tablicy asocjacyjnej, której kluczem jest zapytanie, a wartościami wynik zapytania i czas utworzenia.
  3. Do sprawdzania czy cache nie jest przeterminowany odejmuję liczbę sekund od obecnego czasu i sprawdzam czy jest wcześniejsza od czasu utworzenia danego klucza.
  4. Oczyszczam cache sprawdzając czy poszczególne klucze nie są już przeterminowane i w razie czego wywalam cały klucz.
  5. Do zapisu do pliku używam destruktora. Mam pewność, że obiekt zaraz przed zakończeniem żywota zapisze dane do pliku.

Na koniec przykład użycia całości:

$c = new DBKontener();
$query = $c->selectQuery;
$results = $query->getResults('SELECT nazwa_pola FROM jakas_tabela');

Za pierwszym razem dane zostaną pobrane z bazy, a następnie przez 30 sekund z pliku cache.

Autor wpisu: Tomasz Kowalczyk, dodany: 26.04.2011 23:56, tagi: mysql, symfony, framework, doctrine

W codziennej pracy używamy wielu narzędzi wspomagających naszą pracę przy tworzeniu stron internetowych i wykonywaniu innych usług z tym związanych. Poczynając od IDE, poprzez różnego rodzaju narzędzia konsolowe, aż po wtyczki w przeglądarkach internetowych jesteśmy zależni od wielu tysięcy linii kodu, dzięki którym nasze życie jest o wiele łatwiejsze, niż w przypadku, kiedy musielibyśmy wykonać [...]
Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.