Udostępnij za pośrednictwem


          

PHP na Windows Azure - Mechanizmy przechowywania danych - tabele Udostępnij na: Facebook

Autor: Maciej Wilgucki

Opublikowano: 2011-04-19

Pobierz i uruchom

Azure Storage składa się z trzech mechanizmów przechowywania danych. Są to bloby, kolejki oraz tabele. Dwa pierwsze poznaliśmy w poprzednich artykułach. Dzisiaj zajmiemy się tabelami. Tabele w Azure Storage stanowią nierelacyjny sposób przechowywania danych w postaci encji, gdzie każda z encji stanowi zbiór właściwości. W ramach jednego konta Azure Storage można przechowywać do 100TB danych, przy czym jedna encja nie może przekroczyć 1MB.

Implementacja

Zanim będziemy mogli przechowywać dane w tabelach, musimy je odpowiednio przygotować – zapisać w postaci encji, które ostatecznie trafią do Azure Storage. Encje można definiować na dwa sposoby – ze zdefiniowanym schematem oraz ze schematem dynamicznym.

Encje

Encja ze zdefiniowanym schematem jest klasą dziedziczącą po klasie Microsoft_WindowsAzure_Storage_TableEntity i posiadającą zdefiniowane właściwości. Każda z właściwości musi zostać opisana stosownym komentarzem w celu poprawnego ich zidentyfikowania. Z komentarza możemy zrezygnować, jednak wówczas wszystkie dane zapisane do tabeli będą typu string. Przykładowa encja może mieć następującą postać:

class Encja extends Microsoft_WindowsAzure_Storage_TableEntity
{
    /**
     * @azure Imie
     */
    public $imie;

    /**
     * @azure Nazwisko
     */
    public $nazwisko;

    /**
     * @azure Wiek Edm.Int32
     */
    public $wiek;
}

Komentarze, pokazane powyżej, służą do opisania poszczególnych właściwości – z ich pomocą można zmienić nazwę, pod jaką przechowywane są dane, oraz określić typ danych. Do dyspozycji mamy:

  • Edm.Binary – dane binarne w postaci tablicy o maksymalnym rozmiarze 64KB.
  • Edm.Boolean – wartość logiczna.
  • Edm.DateTime – data w formacie UTC.
  • Edm.Double – wartość zmiennoprzecinkowa.
  • Edm.Guid – unikatowy identyfikator.
  • Edm.Int32 – liczba całkowita 32-bitowa.
  • Edm.Int64 – liczba całkowita 64-bitowa.
  • Edm.String – ciąg znaków.

Encja z dynamicznych schematem definiowana jest w locie i nie wymaga tworzenia klasy. Zamiast tego korzystamy z klasy Microsoft_WindowsAzure_Storage_DynamicTableEntity. Właściwości takiej encji definiowane są w momencie ich użycia:

   $encja = new Microsoft_WindowsAzure_Storage_DynamicTableEntity();
$encja->Imie = 'Jan';
$encja->Nazwisko = 'Kowalski';
$encja->Wiek = 30;

Jeśli chcielibyśmy ustawić inny, niż domyślny, typ danych (którym jest string), mamy możliwość skorzystania z metody setAzurePropertyType:

$encja->setAzurePropertyType('Wiek', 'Edm.Int64');

Oprócz właściwości, które definiujemy sami, każda encja zawiera cztery dodatkowe. Są to:

  • PartitionKey – klucz partycji określający partycję, w której znajduje się encja.
  • RowKey – klucz wiersza, który musi być unikatowy w obrębie partycji.
  • Timestamp – określa datę ostatniej zmiany encji.
  • Etag – znacznik określający wersję encji.

Właściwości PartitionKey oraz RowKey stanowią „klucz główny” tabeli i ich kombinacja musi być unikatowa – po nich można jednoznacznie zidentyfikować każdą z encji.

Operacje na tabelach i encjach

Wiemy już, czym są encje i w jaki sposób je tworzyć. Teraz dowiemy się, jak z nich korzystać. Zaczniemy od utworzenia tabeli:

$host = Microsoft_WindowsAzure_Storage::URL_DEV_TABLE;
$accountName = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT;
$accountKey = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY;

$tableStorageClient = new Microsoft_WindowsAzure_Storage_Table($host, $accountName, $accountKey);
$tableStorageClient->createTableIfNotExists('tabela');

Posiadając utworzoną tabelę, możemy dodać do niej encję. Podczas tworzenia encji musimy pamiętać o nadaniu jej poprawnego klucza partycji oraz klucza wiersza. Próba dodania do tabeli dwóch encji o takich samych wartościach PartitionKey oraz RowKey zakończy się zgłoszeniem błędu.

$encja = new Encja('partycja1', 'wiersz1');
$encja->imie = 'Jan';
$encja->nazwisko = 'Kowalski';
$encja->wiek = 30;
$tableStorageClient->insertEntity('tabela', $encja);

W podobny sposób dokonujemy aktualizacji encji. Tym razem musimy pamiętać, że klucz partycji i klucz wiersza wskazują na encję, którą będziemy modyfikować.

$encja = new Encja('partycja1', 'wiersz1');
$encja->imie = 'Janek';
$encja->nazwisko = 'Kowalski';
$encja->wiek = 20;
$tableStorageClient->updateEntity('tabela', $encja);

Pobranie encji z tabeli możemy wykonać na kilka sposobów. Najprostszym z nich będzie pobranie encji według jej identyfikatora (czyli pary – klucz partycji i klucz wiersza):

$encja = $tableStorageClient->retrieveEntityById('tabela', 'partycja1', 'wiersz1', 'Encja');

Powyższa metoda pobierze z tabeli o nazwie „tabela” encję określoną kluczem partycji o wartości „partycja1” oraz kluczem wiersza „wiersz1”. Ostatni argument funkcji jest opcjonalny, ale warto z niego skorzystać. Określa on typ encji zwróconej przez metodę (w powyższym przykładzie jest to Encja).

Nie jesteśmy ograniczeni do pobierania encji jedynie na podstawie jej identyfikatora. Zamiast tego możemy wykonywać zapytania, podobnie jak w przypadku standardowych baz danych.

$encje = $tableStorageClient->retrieveEntities(
    'tabela',
    'Imie eq \'Janek\'',
    'Encja'
);

Dokładny opis składni wykorzystanej do budowania zapytań można znaleźć pod adresem https://msdn.microsoft.com/en-us/library/dd894031.aspx.

Alternatywnym sposobem tworzenia zapytań jest możliwość skorzystania z łańcuchowego wywoływania metod, znanego chociażby z Zend Frameworka (Zend_Db).

$select = $tableStorageClient->select();
$select->from('tabela')
    ->where('Imie eq ?', 'Janek');

$encje = $tableStorageClient->retrieveEntities(
    $select,
    null,
    'Encja'
);

Warto też wiedzieć o limitach, jakie zostały nałożone na tabele. Na całą operację pobierania danych mamy maksymalnie 30 sekund, przy czym tylko 5 sekund na wykonanie zapytania. Kolejnym ograniczeniem jest limit encji, jakie możemy za jednym razem pobrać. Limit ten wynosi 1000 encji. Jeśli okaże się, że nasze zapytanie zwraca więcej niż 1000 encji lub czas jego wykonywania przekroczy 5 sekund, wówczas z nagłówkach odpowiedzi otrzymamy, oprócz żądanych danych, tokeny kontynuacji. Przekazanie ich w kolejnym żądaniu (dla tych samych parametrów żądania) spowoduje, że dane zostaną zwrócone od miejsca, w którym nastąpiło przerwanie ich pobierania.

Usuwanie encji jest odbywa się podobnie jak ich aktualizacja. Wystarczy wskazać encję do usunięcia i przekazać instancję obiektu jej odpowiadającą do metodydeleteEntity:

$encja = $tableStorageClient->retrieveEntityById('tabela', 'partycja1', 'wiersz1', 'Encja');
$tableStorageClient->deleteEntity('tabela', $encja);

Tabele w Azure Storage oferują jeszcze jedną, bardzo przydatną funkcjonalność – transakcje. Możemy zamknąć blok operacji w transakcji i wycofać wprowadzone zmiany w przypadku wystąpienia jakichkolwiek problemów. Należy jednak pamiętać, że transakcje działają w obrębie tylko jednej partycji (tego samego PartitionKey). Co więcej, jedna encja może zostać użyta tylko jeden raz w całej transakcji, a całkowita liczba encji w jednej transakcji wynosi 100. Wszystkie encje nie mogą przekroczyć rozmiaru 4 MB.

$batch = $tableStorageClient->startBatch();
try {
    for($i=0; $i<10; $i++) {
        $encja = new Encja('partycja1', 'wiersz' . $i);
        $encja->imie = 'Imie ' . $i;
        $encja->nazwisko = 'Nazwisko ' . $i;
        $encja->wiek = (20 + $i);

        // operacje na encji
    }
    $batch->commit();
} catch(Exception $e) {
    $batch->rollback();
}

Zastosowanie

Tabele idealnie nadają się do przechowywania nierelacyjnych danych bez konieczności zachowania schematu danych. Oznacza to, że jeśli część danych wymaga dodatkowych informacji, nie musimy martwić się strukturą danych. Jako przykład niech tutaj posłuży sklep z odzieżą. Jak wiadomo, różne produkty posiadają różne parametry je opisujące. W przypadku butów jest to tylko rozmiar, dla spodni – obwód w pasie i długość nogawki, a rozmiar koszuli określony jest rozmiarem kołnierzyka. W przypadku standardowej bazy danych zmuszeni bylibyśmy do tworzenia nadmiarowych kolumn lub użycia tabel pomocniczych. Azure Tables rozwiązuje ten problem, pozwalając na przechowanie tylko tych informacji, które są rzeczywiście niezbędne.

Podsumowanie

W dzisiejszym artykule poznaliśmy Tabele – trzeci i ostatni zarazem mechanizm przechowywania danych w Azure Storage. Wszystkie trzy sposoby dają ogromne możliwości i połączone razem pozwalają stworzyć w pełni działającą aplikację. Sama aplikacja może znajdować się w chmurze jako rola web lub worker, albo jako aplikacja znajdująca się na dowolnym serwerze, korzystająca z chmury jako magazynu danych.

W następnym artykule zapoznamy się nieco bliżej ze standardowym sposobem przechowywania danych – relacyjną bazę danych SQL Azure.