Ciao, volevo chiedere un consiglio per una classe di gestionde del db che sto sviluppando:
l'apertura e chiusura della connessione al db è meglio implementarla a livello di singola query o a livello di costruttore/distruttore della classe?
Ciao, volevo chiedere un consiglio per una classe di gestionde del db che sto sviluppando:
l'apertura e chiusura della connessione al db è meglio implementarla a livello di singola query o a livello di costruttore/distruttore della classe?
l'apertura/chiusura della connessione è un'operazione molto onerosa e va gestita in maniera oculata. Da qui la scelta di usare
- apertura/chiusura nei distruttori
- uso di connection pool
l'apertura/chiusura ad ogni query direi che sia un suicidio. Attenzione all'implementazione delle transaction
IP-PBX management: http://www.easypbx.it
Old account: 2126 messages
Oldest account: 3559 messages
In che senso "implementazione delle transaction" ? Le transazioni non posso implementarle nella stringa della query? con condizioni e rollback o commit programmati in PL SQL (Oracle)
Posto la classe ipotetica, al fine di trovarne i difetti! Il problema che verifico è fino ad ora solo un Warning nel momento in cui effettuo un inserimento:
Warning: oci_fetch(): ORA-24374: define not done before fetch or execute and fetch in .../dbManager.php on line ..(praticamente quando faccio la oci_fetch.
ecco la classe:
<?php
class dbManager {
// Definizione degli Attributi di classe
private $dbh; // Connettore database
private $dbUser; // Utente del database
private $dbPwd; // Password utente
private $dbName; // Nome del database
private $charset; // Charset
private $stat; // Statement per l'esecuzione della query
// Metodo costruttore
public function __construct(){
// Valorizzo i dati per la connessione al database (ESEMPIO)
$this->dbUser = 'xxxx';
$this->dbPwd = 'yyyy';
$this->dbName = 'wwww';
$this->charset = 'zzzz';
$this->dbOpenConn();
}
/*
* ************************************************** ************
*
* METODI PRIVATI
*
* ************************************************** ************
*/
// Metodo per connettersi al database
private function dbOpenConn(){
$this->dbh = oci_connect($this->dbUser,$this->dbPwd,$this->dbName,$this->charset);
}
// Metodo per disconnettere il database
private function dbCloseConn(){
oci_close($this->dbh);
}
// Metodo per fare il parsing della query
private function dbParseQuery($query){
$this->stat = oci_parse($this->dbh,$query);
if (!$this->stat){
echo oci_error($this->stat);
exit();
}
}
// Metodo per eseguire la query
private function dbExecuteQuery(){
if (!oci_execute($this->stat)){
echo oci_error($this->stat);
exit();
}
}
// Metodo per il bind delle variabili
private function dbBind($query,$params){
$nomi = array();
$valori = array();
// Recupero i nomi e i valori delle variabili
foreach ($params as $v_name => $v_value){
$nomi[] = $v_name;
$valori[] = $v_value;
}
// Eseguo il bind per ogni coppia nome->valore
for ($i=0;$i<count($nomi);$i++)
oci_bind_by_name($this->stat,$nomi[$i],$valori[$i]);
}
/*
* Metodo per costruire l'array dei risultati in modo numerico.
* Se il risultato è un insieme di record, si ha una matrice avente
* tante righe quanti sono i risultati della query (da 0 a n-1).
* Se il risultato è un solo record invece ritorna un array con i valori
* risultanti
*/
private function dbNumericResult(){
// Uso un contatore per assegnare le righe
$j = 0;
$result = array();
while (oci_fetch($this->stat)){
// Ogni elemento dell'array è un array di posti pari al numero di colonne
// Se ho una sola colonna carico l'array monodimensionale
if (oci_num_fields($this->stat) == 1){
$result[] = oci_result($this->stat,1);
}
// Se ho più di una colonna, uso un array bidimensionale
else{
// Per ogni colonna aggiungo aggiungo il valore ritornato dalla query
for ($i=0;$i<oci_num_fields($this->stat);$i++){
$result[$j][$i] = oci_result($this->stat,$i+1);
}
$j++;
}
}
if (count($result) == 1)
return $result[0];
return $result;
}
/*
* Metodo per costruire l'array associativo dei risultati
* Se il risultato è un insieme di record, si ha una matrice in cui ogni riga
* è rappresentata da un numero e ogni campo dal nome dello stesso. Se invece
* si ha un unico record, il metodo ritorna un array associativo.
*/
private function dbAssociativeResult(){
$result = array();
// Se seleziono una sola colonna ottengo un array numerico
if (oci_num_fields($this->stat) == 1)
while (oci_fetch($this->stat))
$result[] = oci_result($this->stat,1);
else{
while ($result[] = oci_fetch_array($this->stat,OCI_ASSOC)){}
/* L'ultima assegnazione è vuota perchè la condizione non si verifica
* quindi tolgo l'ultimo elemento dall'array, altrimenti se ne conta
* uno in più
*/
unset($result[count($result)-1]);
}
if (count($result) == 1)
return $result[0];
return $result;
}
/*
* ************************************************** ************
*
* METODI PUBBLICI
*
* ************************************************** ************
*/
// Metodo per eseguire insert o update
public function querySqlInsUpDel($query){
// Parsing della query SQL
$this->dbParseQuery($query);
// Esecuzione della query
$this->dbExecuteQuery();
return;
}
// Metodo per eseguire insert o update con bind
public function querySqlBindInsUpDel($query,$params){
// Parsing della query SQL
$this->dbParseQuery($query);
// Bind delle variabili
$this->dbBind($query,$params);
// Esecuzione della query
$this->dbExecuteQuery();
return;
}
/*
* Metodo per eseguire query sql
*
* note: questo metodo effettua la query e ritorna un array numerico monodimensionale
* se si è selezionato un solo attributo, e un array numerico bidimensionale
* se si è selezionato un insieme di attributi.
*/
public function querySql($query){
// Parsing della query SQL
$this->dbParseQuery($query);
// Esecuzione della query
$this->dbExecuteQuery();
// Costruisco l'array dei risultati in modo numerico
$result = $this->dbNumericResult();
// L'array (monodimensionale o multidimensionale) è caricato
return $result;
}
/*
* Metodo per eseguire query sql con ritorno di un array associativo
*
* note: questo metodo effettua la query e ritorna un array monodimensionale
* numerico se si è selezionato un solo attributo, e un array
* bidimensionale numerico/associativo se si è selezionato un insieme
* di attributi.
*/
public function querySqlAssoc($query){
// Parsing della query SQL
$this->dbParseQuery($query);
// Esecuzione della query
$this->dbExecuteQuery();
// Costruisco l'array dei risultati in modo associativo
$result = $this->dbAssociativeResult();
// L'array (monodimensionale o multidimensionale) è caricato
return $result;
}
/*
* Metodo per eseguire query sql con bind di variabili
*
* note: questo metodo effettua la query e ritorna un array numerico monodimensionale
* se si è selezionato un solo attributo, e un array numerico bidimensionale
* se si è selezionato un insieme di attributi.
*/
public function querySqlBind($query,$params){
// Parsing della query SQL
$this->dbParseQuery($query);
// Bind delle variabili
$this->dbBind($query,$params);
// Esecuzione della query
$this->dbExecuteQuery();
// Costruisco l'array dei risultati in modo numerico
$result = $this->dbNumericResult();
// L'array (monodimensionale o multidimensionale) è caricato
return $result;
}
/*
* Metodo per eseguire query sql con ritorno di un array associativo e bind di variabili
*
* note: questo metodo effettua la query e ritorna un array monodimensionale
* numerico se si è selezionato un solo attributo, e un array
* bidimensionale numerico/associativo se si è selezionato un insieme
* di attributi.
*/
public function querySqlAssocBind($query,$params){
// Parsing della query SQL
$this->dbParseQuery($query);
// Bind delle variabili
$this->dbBind($query,$params);
// Esecuzione della query
$this->dbExecuteQuery();
// Costruisco l'array dei risultati in modo numerico
$result = $this->dbAssociativeResult();
// L'array (monodimensionale o multidimensionale) è caricato
return $result;
}
// Metodo distruttore
public function __destruct(){
// Chiudo
$this->dbCloseConn();
}
}
?>
Sono ben accetti commenti/proposte/soluzioni e qualsiasi cosa vi venga in mente!
implementare le transaction nel senso che io magari vorrei fare:
Il fatto che con la tua classe tu non possa scegliere quando aprire e chiudere la connessione in maniera implicita, io la vedo un pò come una limitazione. Il non poter aprire/chiudere transazioni indipendentemente da eventuali procedure impostate nel db, la vedo come una limitazione. L'handler degli errori usando echo e exit, la vedo come un errore: usa throw per lanciare eccezioni catturabili con try/catch dalle classi/Script che usano questa classe. Il resto poi non l'ho guardatoCodice PHP:
//da qualche parte nella mia app
$conn = new dbManager();
....
//ad un certo punto apro la connessione
$conn->open();
....
//eseguo query varie
$ret = $conn->executeQuery("my sql");
...
//voglio fare una transazione
$conn->begin();
$ret = $conn->executeQuery("my sql");
if(!$ret)
$conn->rollback();
else
$conn->commit();
...
//fine sezione con il dbManager
$conn->close();
ps: usa i tag [ P H P ] e [ / P H P ] per includere codici php che altrimenti sono poco leggibli
IP-PBX management: http://www.easypbx.it
Old account: 2126 messages
Oldest account: 3559 messages
nn ti conviene usare PDO che ha anche un parametro per le connessioni persistenti??
il driver per oracle (PDO_OCI) è settato come "sperimentale" in php.net, non mi sembra una scelta oculata usarlo.Originariamente inviato da fermat
nn ti conviene usare PDO che ha anche un parametro per le connessioni persistenti??
IP-PBX management: http://www.easypbx.it
Old account: 2126 messages
Oldest account: 3559 messages
ah ok nn sapevo.Originariamente inviato da Santino83_02
il driver per oracle (PDO_OCI) è settato come "sperimentale" in php.net, non mi sembra una scelta oculata usarlo.
allora direi proprio di no.
Scusate, avete ragione. Ma le operazioni sono corrette o manca qualche controllo? Valuterò singolarmente i vostri suggerimenti, per i quali intanto vi ringrazio.
Codice PHP:
<?php
class dbManager {
// Definizione degli Attributi di classe
private $dbh; // Connettore database
private $dbUser; // Utente del database
private $dbPwd; // Password utente
private $dbName; // Nome del database
private $charset; // Charset
private $stat; // Statement per l'esecuzione della query
// Metodo costruttore
public function __construct(){
// Valorizzo i dati per la connessione al database (ESEMPIO)
$this->dbUser = 'xxxx';
$this->dbPwd = 'yyyy';
$this->dbName = 'wwww';
$this->charset = 'zzzz';
$this->dbOpenConn();
}
/*
* **************************************************************
*
* METODI PRIVATI
*
* **************************************************************
*/
// Metodo per connettersi al database
private function dbOpenConn(){
$this->dbh = oci_connect($this->dbUser,$this->dbPwd,$this->dbName,$this->charset);
}
// Metodo per disconnettere il database
private function dbCloseConn(){
oci_close($this->dbh);
}
// Metodo per fare il parsing della query
private function dbParseQuery($query){
$this->stat = oci_parse($this->dbh,$query);
if (!$this->stat){
echo oci_error($this->stat);
exit();
}
}
// Metodo per eseguire la query
private function dbExecuteQuery(){
if (!oci_execute($this->stat)){
echo oci_error($this->stat);
exit();
}
}
// Metodo per il bind delle variabili
private function dbBind($query,$params){
$nomi = array();
$valori = array();
// Recupero i nomi e i valori delle variabili
foreach ($params as $v_name => $v_value){
$nomi[] = $v_name;
$valori[] = $v_value;
}
// Eseguo il bind per ogni coppia nome->valore
for ($i=0;$i<count($nomi);$i++)
oci_bind_by_name($this->stat,$nomi[$i],$valori[$i]);
}
/*
* Metodo per costruire l'array dei risultati in modo numerico.
* Se il risultato è un insieme di record, si ha una matrice avente
* tante righe quanti sono i risultati della query (da 0 a n-1).
* Se il risultato è un solo record invece ritorna un array con i valori
* risultanti
*/
private function dbNumericResult(){
// Uso un contatore per assegnare le righe
$j = 0;
$result = array();
while (oci_fetch($this->stat)){
// Ogni elemento dell'array è un array di posti pari al numero di colonne
// Se ho una sola colonna carico l'array monodimensionale
if (oci_num_fields($this->stat) == 1){
$result[] = oci_result($this->stat,1);
}
// Se ho più di una colonna, uso un array bidimensionale
else{
// Per ogni colonna aggiungo aggiungo il valore ritornato dalla query
for ($i=0;$i<oci_num_fields($this->stat);$i++){
$result[$j][$i] = oci_result($this->stat,$i+1);
}
$j++;
}
}
if (count($result) == 1)
return $result[0];
return $result;
}
/*
* Metodo per costruire l'array associativo dei risultati
* Se il risultato è un insieme di record, si ha una matrice in cui ogni riga
* è rappresentata da un numero e ogni campo dal nome dello stesso. Se invece
* si ha un unico record, il metodo ritorna un array associativo.
*/
private function dbAssociativeResult(){
$result = array();
// Se seleziono una sola colonna ottengo un array numerico
if (oci_num_fields($this->stat) == 1)
while (oci_fetch($this->stat))
$result[] = oci_result($this->stat,1);
else{
while ($result[] = oci_fetch_array($this->stat,OCI_ASSOC)){}
/* L'ultima assegnazione è vuota perchè la condizione non si verifica
* quindi tolgo l'ultimo elemento dall'array, altrimenti se ne conta
* uno in più
*/
unset($result[count($result)-1]);
}
if (count($result) == 1)
return $result[0];
return $result;
}
/*
* **************************************************************
*
* METODI PUBBLICI
*
* **************************************************************
*/
// Metodo per eseguire insert o update
public function querySqlInsUpDel($query){
// Parsing della query SQL
$this->dbParseQuery($query);
// Esecuzione della query
$this->dbExecuteQuery();
return;
}
// Metodo per eseguire insert o update con bind
public function querySqlBindInsUpDel($query,$params){
// Parsing della query SQL
$this->dbParseQuery($query);
// Bind delle variabili
$this->dbBind($query,$params);
// Esecuzione della query
$this->dbExecuteQuery();
return;
}
/*
* Metodo per eseguire query sql
*
* note: questo metodo effettua la query e ritorna un array numerico monodimensionale
* se si è selezionato un solo attributo, e un array numerico bidimensionale
* se si è selezionato un insieme di attributi.
*/
public function querySql($query){
// Parsing della query SQL
$this->dbParseQuery($query);
// Esecuzione della query
$this->dbExecuteQuery();
// Costruisco l'array dei risultati in modo numerico
$result = $this->dbNumericResult();
// L'array (monodimensionale o multidimensionale) è caricato
return $result;
}
/*
* Metodo per eseguire query sql con ritorno di un array associativo
*
* note: questo metodo effettua la query e ritorna un array monodimensionale
* numerico se si è selezionato un solo attributo, e un array
* bidimensionale numerico/associativo se si è selezionato un insieme
* di attributi.
*/
public function querySqlAssoc($query){
// Parsing della query SQL
$this->dbParseQuery($query);
// Esecuzione della query
$this->dbExecuteQuery();
// Costruisco l'array dei risultati in modo associativo
$result = $this->dbAssociativeResult();
// L'array (monodimensionale o multidimensionale) è caricato
return $result;
}
/*
* Metodo per eseguire query sql con bind di variabili
*
* note: questo metodo effettua la query e ritorna un array numerico monodimensionale
* se si è selezionato un solo attributo, e un array numerico bidimensionale
* se si è selezionato un insieme di attributi.
*/
public function querySqlBind($query,$params){
// Parsing della query SQL
$this->dbParseQuery($query);
// Bind delle variabili
$this->dbBind($query,$params);
// Esecuzione della query
$this->dbExecuteQuery();
// Costruisco l'array dei risultati in modo numerico
$result = $this->dbNumericResult();
// L'array (monodimensionale o multidimensionale) è caricato
return $result;
}
/*
* Metodo per eseguire query sql con ritorno di un array associativo e bind di variabili
*
* note: questo metodo effettua la query e ritorna un array monodimensionale
* numerico se si è selezionato un solo attributo, e un array
* bidimensionale numerico/associativo se si è selezionato un insieme
* di attributi.
*/
public function querySqlAssocBind($query,$params){
// Parsing della query SQL
$this->dbParseQuery($query);
// Bind delle variabili
$this->dbBind($query,$params);
// Esecuzione della query
$this->dbExecuteQuery();
// Costruisco l'array dei risultati in modo numerico
$result = $this->dbAssociativeResult();
// L'array (monodimensionale o multidimensionale) è caricato
return $result;
}
// Metodo distruttore
public function __destruct(){
// Chiudo
$this->dbCloseConn();
}
}
In merito alla questione delle transazioni, se come query passo una cosa del genere:
"insert into <tabella> <ecc..> ;
if <condizione> then
commit;
else
rollback;
end if;
"
non sto eseguendo perfettamente una transazione??
Originariamente inviato da Santino83_02
implementare le transaction nel senso che io magari vorrei fare:
Il fatto che con la tua classe tu non possa scegliere quando aprire e chiudere la connessione in maniera implicita, io la vedo un pò come una limitazione. Il non poter aprire/chiudere transazioni indipendentemente da eventuali procedure impostate nel db, la vedo come una limitazione. L'handler degli errori usando echo e exit, la vedo come un errore: usa throw per lanciare eccezioni catturabili con try/catch dalle classi/Script che usano questa classe. Il resto poi non l'ho guardatoCodice PHP:
//da qualche parte nella mia app
$conn = new dbManager();
....
//ad un certo punto apro la connessione
$conn->open();
....
//eseguo query varie
$ret = $conn->executeQuery("my sql");
...
//voglio fare una transazione
$conn->begin();
$ret = $conn->executeQuery("my sql");
if(!$ret)
$conn->rollback();
else
$conn->commit();
...
//fine sezione con il dbManager
$conn->close();
ps: usa i tag [ P H P ] e [ / P H P ] per includere codici php che altrimenti sono poco leggibli
se programmi direttamente nel database si, ma quando programmi in un linguaggio esterno al database solitamente si fa, ad esempio, come ti ho detto io. Anche perchè lo scopo di fondo sarebbe gestire meno sql possibile...tu addirittura ci gestisci la transazione.
Per quanto riguarda la tua classe, non so che dirti. Funzionerà secondo il modo che tu hai impostato di usarla (errore a parte, ma non ho un db oracle su cui fare un test), però secondo me ha una serie di problemi concettuali che in parte ho già esposto nell'esempio sopra. Poi in un contesto oop le mancanze risultano palesi e darebbero fastidio nella programmazione. In un contesto di scripting probabilmente ha anche un suo senso, anche se io metterei l'apertura della connessione "opzionabile", e la chiusura fissa nel distruttore per essere sicuri che, se aperta, la connessione venga chiusa
IP-PBX management: http://www.easypbx.it
Old account: 2126 messages
Oldest account: 3559 messages