Autor Zpráva
Fisak
Profil
Dobrý den. Potřeboval bych pomoci s řešením situace která mi právě nastala. Mám v mém systému 3 DB -> pro uživatele zvlášť pro systém zvlášť a pro obsah zvlášť db. U vertriga nebo u Endory to funguje tak že všechny db uživatele mají společný server user i pass. Rozdíl je zde jen v názvech DB. Jenže sem narazil na hosting kde je ke každé db zvlášť user heslo i název db. Společný zde mají jen server. Můj skript pro spojení s DB do teďka fungoval takto
<?php
abstract class database{

    static function connect($db_name) {

    if(!mysql_connect(_DB_SERVER_,_DB_USER_,_DB_PASSWD_)){
    
        return mysql_error();

    } else {

        if(!mysql_select_db($db_name)){

             return "Nepodařilo se vybrat databázi $db_name.";
         
        } else {
    
            mysql_query("SET character_set_results = utf8");
            mysql_query("SET character_set_connection = utf8"); 
            mysql_query("SET NAMES utf8");
        
        } 
     
    }
      
    }

}

class db extends database {

    //připojení k databázy system    
    static function query_system($retezec)
    {
        static $connected_sys = false; 
        if($connected_sys === false) db::connect(_DB_NAME_SYSTEM_);  

        return mysql_query($retezec); 
    }

    //pripojení k databázy uživatelu
    static function query_users($retezec)
    {
        static $connected_us = false; 
        if($connected_us === false) db::connect(_DB_NAME_USERS_);

        return mysql_query($retezec); 
    }

    //pripojení k databázy obsahu
    static function query_content($retezec)
    {
        static $connected_cont = false; 
        if($connected_cont === false) db::connect(_DB_NAME_CONTENT_);

        return mysql_query($retezec); 
    }

}

Jenže jak tento skript upravit tak aby co nejméně zatěžoval server s neustálím spojováním s DB při každém dotazu. Prosím o radu. Ale neprosím o radu abych začal používat dibi nebo již něco vytvořeného.
Předem děkuji za odpověď.
Kajman
Profil
Pamatujte si identifikátor těch tří (v tomto případě) různých připojení a předávejte ho jako parametry v mysql_query.

Případně prozkoumejte, zda nemůžete z dvou uživatelských účtů povolit jednomu hlavnímu, aby pracoval s jejich tabulkami (příkazem grant).
Fisak
Profil
Kajman:
Případně prozkoumejte, zda nemůžete z dvou uživatelských účtů povolit jednomu hlavnímu, aby pracoval s jejich tabulkami (příkazem grant).
bohužel to nelze u mého webhostingu z toho co jsem pochopil od podpory wedosu. A jak se pamatují identifikátory těchto tří db ??
Kajman
Profil
Fisak:
A jak se pamatují identifikátory těchto tří db ?

V proměnných.
http://cz.php.net/manual/en/language.oop5.properties.php
Fisak
Profil
Vyřešil sem to takto. Ale i když to funguje tak nevím jestli je to dobré.
<?php
abstract class database{

    static function connect($db_name) {

    if($db_name == "system") { $db_server_db = _DB_SERVER_SYSTEM_; $db_user_db = _DB_USER_SYSTEM_; $db_pass_db = _DB_PASSWD_SYSTEM_; $db_name_db = _DB_NAME_SYSTEM_; }
    elseif($db_name == "users") { $db_server_db = _DB_SERVER_USERS_; $db_user_db = _DB_USER_USERS_; $db_pass_db = _DB_PASSWD_USERS_; $db_name_db = _DB_NAME_USERS_; }
    elseif($db_name == "content") { $db_server_db = _DB_SERVER_CONTENT_; $db_user_db = _DB_USER_CONTENT_; $db_pass_db = _DB_PASSWD_CONTENT_; $db_name_db = _DB_NAME_CONTENT_; }
    else die('Mysql error!');
    
    if(!mysql_connect($db_server_db,$db_user_db,$db_pass_db)){
    
        return mysql_error();

    } else {

        if(!mysql_select_db($db_name_db)){

             return "Nepodařilo se vybrat databázi $db_name.";
         
        } else {
    
            mysql_query("SET character_set_results = utf8");
            mysql_query("SET character_set_connection = utf8"); 
            mysql_query("SET NAMES utf8");
        
        } 
     
    }
      
    }

}


class db extends database {

    //připojení k databázy system    
    static function query_system($retezec)
    {
        static $connected_sys = false; 
        if($connected_sys === false) db::connect("system");  

        return mysql_query($retezec); 
    }

    //pripojení k databázy uživatelu
    static function query_users($retezec)
    {
        static $connected_us = false; 
        if($connected_us === false) db::connect("users");

        return mysql_query($retezec); 
    }

    //pripojení k databázy obsahu
    static function query_content($retezec)
    {
        static $connected_cont = false; 
        if($connected_cont === false) db::connect("content");

        return mysql_query($retezec); 
    }

}
Tori
Profil
Připadá mi to příliš jednorázové, nemůžete to bez úprav použít v jiném projektu. Porušené zapouzdření - spoléháte na existenci nějakých konstant. Třída si nárokuje řízení celé aplikace - použití die. U každého dotazu se snažíte navázat nové připojení s DB (pokud použijete dvakrát za sebou stejné přihl.údaje, tak se sice použije předchozí připojení, ale je zbytečné xkrát volat mysql_connect, když můžete uložit její výsledek a ten přidávat jako 2.param mysql_query). Pokud přidáte další databázi, musíte dopsat další sadu metod.

Zkuste na to jít z opačné strany, jak byste chtěl třídu použít, jaké rozhraní má třída mít. Když si představím, že bych měla používat paralelně 3 databáze (a případně za 2 roky ten kód znova upravovat), tak bych chtěla mít rozhraní snadno čitelné/pochopitelné a taky aby se "za oponou" neděly žádné nečekané věci (např. že překlep v konfiguráku shodí celou aplikaci). Třeba by mi připadalo použitelné něco takovéhoto ↓, takže bych rozhraní třídy udělala podle toho.
try {
    $db = new Database;
    $db->connect($config['db']['system'] /* přihlašovací údaje + kódování */, 'system' /* nepovinný identifikátor tohoto připojení */ );
    $db->connect($config['db']['users'], 'users');
    $db->connect($config['db']['content'], 'content');
} catch (DbConnectionError $e) {
    /* Některé připojení selhalo */
    Log::write($e->getMessage());
}

try {
    // přihlášení:
    // metoda escape escapuje jako řetězec (s doplněním uvozovek okolo) nebo jako číslo, podle toho, jaké znaky vstup obsahuje.
    // 2.parametr je (výše zadaný) identifikátor databáze. Podle něj se interně jako druhý param. mysql_query
    //   použije identifikátor připojení k DB. Pokud ještě nebylo připojení navázáno, provede se to před dotazem.
    //   Pokud není 2.param. zadaný a existuje pouze jedno připojení (nebo přihl.údaje pro něj), použije se to.
    $userData = $db->query('SELECT * FROM `users` WHERE `username` = '.$db->escape($_POST['login']), 'users');
    
    // načtení obsahu:
    $content = $db->query('SELECT `nadpis`, `obsah` FROM `stranky` WHERE `id` = '.$db->escape($router->urlParam['id_stranky']), 'content');
    
} catch (DbQueryError $e) {
    Log::write($e->getMessage());
    // nějaké další zpracování chyby, přesměrování apod.
}
Kód je jen pro ilustraci myšlenky, lidi šikovnější v OOP by tomu určitě oprávněně vytkli x věcí.
Fisak
Profil
a mohu se zeptat ještě jak by tedy vypadal konečný dotaz na db ??? zvlášť pro db users zvlášť pro db system a zvlášť pro db content ??
Tori
Profil
Myslíte rozhraní nebo implementaci?
Fisak
Profil
no myslím např. "query("insert into table ... prostě dotaz", content);" třeba takto ale nevím právě jak by měl fungovat tent Váš skript..
Amunak
Profil
Tori:
Nebylo by lepší mít každé připojení jako jeden objekt:
$dbsys = new Database;
$dbsys->connect(...);
$dbusr = new Database;
$dbusr->connect(...);
$dbsys->query(...)->disconnect();

Přijde mi divné takhle spolu spojovat tři věci. To spíš když už by mohl být "nástavbový" objekt connection který by akorát pomáhal vybrat jednu z těch tří databází (a uměl by s připojeními/databázemi pracovat - nastavovat výchozí, pamatovat si poslední použitou, připojení ukončovat a vytvářet nebo tak) ale prijde mi to spíš zbytečné.
Tori
Profil
Amunak:
Chtěla jsem napsat, že to už bych radši objekt connection schovala někde do soukromé proměnné Database::$connection, a že by mohly být odlišné drivery pro různé DB (aspoň mysql a mysqli, aby se nemusela řešit odlišná syntax SQL), ale vlastně pak už by z toho vyšlo zárodečné stadium dibi. :-)
Ale je pravda, že ten druhý parametr query(), teda přepínač použité databáze, tam nemá být, protože mění chování metody. Takže pokud by Fisak nechtěl rovnou použít Dibi ($result = dibi::getConnection('system')->query('...');), tak váš návrh je lepší.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: