|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Member
Iscritto dal: Jan 2004
Messaggi: 173
|
[Java] Struttura programma per accesso ad un DB
Sto realizzando un’applicazione che si connette ad un database Access ma ho i seguenti dubbi:
Immaginiamo di avere un oggetto persona, il quale incapsula i dati presenti in un record della tabella persone presente nel DB. Questo oggetto mette a disposizione il metodo setAltezza(int altezza), chiaramente lo scopo di questo metodo è quello di aggiornare la tabella del DB. A questo punto mi chiedo: • Conviene aprire una connessione ogni volta che viene richiamato il metodo? • Aprire la connessione nel costruttore e chiuderla nel metodo finalize()? • Creare un oggetto che incapsuli una connessione, passandolo come parametro nel costruttore della classe Persona? • È proprio l’idea della classe Persona che è concettualmente sbagliata? Creo una classe per accedere al database e basta, rinunciando all’astrazione che permette la classe Persona? • Ma quante connessioni è possibile avere in contemporanea con Access? • Sto sbagliando tutto? Chiaramente ho fatto i miei esperimenti usando il driver bridge JDBC-ODBC, ho notato che aprire e chiudere una connessione comporta dei malfunzionamenti senza alcuna eccezione. Tuttavia non so quanto sia conveniente tenere aperte molte connessioni. Grazie in anticipo per ogni consiglio. |
|
|
|
|
|
#2 | |||||||
|
Junior Member
Iscritto dal: Apr 2002
Messaggi: 10
|
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Ovviamente il tutto è in tono molto ironico... credo che ti convenga studiare bene la teoria della programmazione ad oggetti. Ti studi qualche bel pattern... Il consiglio che posso darti è di "dividere" i compiti alle singole classi... La classe Persona incapsula i dati della persona e se gli attribuisci anche il compito della persistenza (come avviene negli Entity Bean ad esempio), la cosa si complica un po' per problemi di sincronizzazione, accesso concorrente e balle varie... Ti fai una bella classettina che ti gestisce le connessioni (anche nn in pool) semplice semplice (apri, chiudi) e una bella classettina che esegue le singole operazioni (legge, inserisce, aggiorna, elimina) Non è una soluzione elegante ma almeno hai diviso i compiti tra le varie classi Spero di esserti stato utile... |
|||||||
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Ciao,
per prima cosa, fai qualche valutazione: - Quanti e quali oggetti devono girare nel tuo applicativo (fai una stima di massima); - Come interagiscono fra di loro (devi cercare di individuare quanti, fra di loro, vanno a "pestarsi i piedi" l'uno con l'altro per accedere al database); Quando hai fatto queste valutazioni, potrai decidere piu' tranquillamente. Ad ogni modo, le connessioni al database sono in numero piuttosto limitato, ed aprire una connessione e' un'operazione dispendiosa (in termini di tempo e di risorse di sistema). Inoltre, piu' connessioni apri, piu' rischi di perderne a seguito, per esempio, di qualche bug nel software (li facciamo tutti,no?). Personalmente non sono a favore della creazione di classi per incapsulare il lavoro fatto da Connessioni e Statement... naturalmente non conosco l'applicativo e ti prego di scusarmi se il commento e' fuori luogo, ma esperienza insegna che il 90% delle classi cosi' partorite finiscono solo con il limitare l'uso delle classi originali. Insomma, si scrive codice per limitarsi... L'idea di aprire una connessione ad ogni chiamata di metodo (a meno che non chiami questo metodo raramente) non sembrerebbe vantaggiosa. Il fatto di avere un oggetto Persona che gestisca anche il suo record nella tabella, invece, e' carina. Fai solo attenzione al fatto che, quando l'applicazione cresce (e magari e' composta da parecchi thread) si potrebbero creare di problemi di consistenza (ovviamente dipende dalle operazioni che serve implementare). High Flying Sottovento |
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Credo che l'idea dell'oggetto Persona ed il problema che si è posto circa la sua persistenza dimostri come carosene abbia ben chiaro cosa sia l'orientamento agli oggetti (almeno per come lo vedo io).
L'uso del metodo finalize() per compiere operazioni di "pulizia" non è in sè errato ma occorre tener conto che esso è certamente efficace solo per gli oggetti che la JVM consideri "short-lived" (non sopravvivono ad un certo numero di puliture della regione di memoria dedicata ai nuovi arrivati). Quando un oggetto passa da short-lived a long-lived, la sua "finalizzazione" può diventare eventuale. La JVM può essere infatti impostata per espandere le dimensioni dell'heap fino al limite prima di liberare la memoria occupata dagli oggetti vegliardi ed è ben possibile che tale limite non sia mai raggiunto, cosa che rimanda la liberazione delle connessioni al momento dello spegnimento dolce (esaurimento dei Thread in esecuzione) della JVM. Se tale tipo di spegnimento non si verifichi, è inoltre possibile che la connessione sopravviva alla JVM. Anche quella di creare un oggetto che incapsuli la base dati è un'intuizione molto "OO" e, più generale, ottima per quanto riguarda l'approccio alla scrittura di un'applicazione, se consideriamo "bene" isolare quelle inevitabili parti di un sistema che siano dipendenti da risorse esterne alla logica dell'applicazione. Potremmo pensare ad una cosa del genere: Codice:
public abstract class DBObject {
private Database database = DBFactory.getDatabase(); //ipotesi
public void set(DBObject who, Object field, Object newValue) {
database.update(who, field, newValue);
}
public Object get(DBObject who, Object field) {
return database.get(who, field);
}
}
e poi: Codice:
public class Persona extends DBObject {
public void setAltezza(int altezza) {
update(this, "altezza", altezza);
}
public int getAltezza() {
return get(this, "altezza");
}
}
Puoi aprirne e chiuderne una ad ogni invocazione di update o get ma noterei come la presenza di un delegato alla gestione della persistenza delle "persone" favorisca l'ipotesi di una connessione unica. |
|
|
|
|
|
#5 |
|
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Ciao,
penso che PGI-Bis abbia sintetizzato in maniera superlativa quanto c'era da dire sul problema. Volevo solo aggiungere che, probabilmente, l'oggetto Persona avra' altri attributi e caratteristiche oltre a quelle di accedere ad un database. Per questo motivo eviterei una struttura di specializzazione e mi rivolgerei verso un meccanismo di aggregazione. Ovviamente l'ultima parola spetta a te, che conosci il problema. High Flying Sottovento |
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: Jul 2004
Città: Roma
Messaggi: 2094
|
Quote:
nella setAltezza non dovresti richiamare set invece che update? ciao e scusami ancora |
|
|
|
|
|
|
#7 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Sbagli!!! Infatti gli errori sono due, non uno
Pardon, ho scritto il codice mentre pensavo a che codice scrivere e poi l'ho cambiato al volo tanto per aumentare la probabilità di scrivere castronerie. Fermo restando lo scopo di esemplificare un'idea, la forma meno imbarazzante avrebbe potuto essere: Codice:
public class Persona extends DBObject {
public void setAltezza(int altezza) {
set(this, "altezza", altezza);
}
public int getAltezza() {
Object value = get(this, "altezza");
if(value instanceof Number) {
return ((Number)value).intValue();
} else {
throw new RuntimeException("Poffare, una stranezza!");
}
}
}
|
|
|
|
|
|
#8 | |
|
Senior Member
Iscritto dal: Jul 2004
Città: Roma
Messaggi: 2094
|
Quote:
beh io non ho capito esattamente che fa il getAltezza adesso come adesso che fai... fai il get di "altezza" e controlli se è un numero...se è un numero cosa fai esattamente? cosa ritorni? Ovvero che vuol dire questo: return ((Number)value).intValue(); Altrimenti se non è un numero c'è un eccezione? giusto? è solamente una finezza? scusa per le domande niubbe |
|
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Premetto che è solo un'idea di funzionamento, nel concreto è possibile che ci siano soluzioni migliori.
getAltezza, come rilevi, deve restituire un int. DBObject permette lo scambio di riferimenti Object tra il richiedente e l'ipotetica base dati. Così ipotizzo che la base dati legga un "int" (che non è un Object), lo incapsuli in un Integer (che è un Object), e lo restituisca come valore per il "get(DBObject, Object)" a cui si appoggia "getAltezza". Ciò che per contratto è un Object, in getAltezza è presupposto Integer. Al livello di getAltezza non è strettamente necessario sapere che il valore ottenuto sia un Tipo Integer. Ciò che conta è che sia un valore numerico intero che, nel campo dei "wrapper" (Byte, Short, Integer, Float, Double), è rappresentato da Number. Così converto quell'Object in Number. Il tipo Number definisce, tra gli altri, il metodo "intValue" che restituisce il valore del numero (che potrebbe essere un qualsiasi wrapper di primitivo) come "int". Che quell'Object sia un Number è però tutt'altro che certo, in Persona. Il fatto che "value" NON sia un Number è, per getAltezza, un'eccezione. Un'eccezione è una condizione il cui verificarsi impedisce ad un'istruzione o ad un blocco di istruzioni, accomunate dall'identità di scopo, di adempiere con successo allo scopo che le accomuna. Secondo una certa teoria delle eccezioni, poichè il verificarsi dell'errore eccezionale non dipende da un comportamento di chi invochi il metodo getAltezza, la notifica del mancato raggiungimento dell'obiettivo (restituire un valore per l'altezza) deve essere segnalata attraverso un'eccezione non controllata. Questa è la ragione della conversione di value a Number, dell'invocazione di intValue e del rilascio di un'eccezione RuntimeException (e non, per dire, un Exception semplice). |
|
|
|
|
|
#10 | |
|
Senior Member
Iscritto dal: Jul 2004
Città: Roma
Messaggi: 2094
|
Quote:
grazie tante purtroppo lavorare in Siebel fa questi brutti scherzi |
|
|
|
|
|
|
#11 |
|
Member
Iscritto dal: Jan 2004
Messaggi: 173
|
Sono giunto a questa conclusione:
Codice:
import java.sql.*;
public abstract class DBObject {
private static Connection cn;
/**
* Registra il driver,inizializza cn...
*/
public static void avviaConnessione() throws SQLException{
...
}
/**
* Chiude cn
*/
public static void terminaConnessione() throws SQLException{
...
}
/**
* Esegue la query passata come parametro per operazioni di selezione
*/
public ResultSet seleziona(String query){
...
}
/**
* Esegue la query passata come parametro
* @return Restituisce il numero dei record modificati
*/
public int update(String query){
...
}
}
Cosa ne pensate? Ultima modifica di carosene : 23-03-2006 alle 10:36. |
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Alla fine della fiera, devi decidere tu quale sia l'approccio che meglio si addice al sistema che vuoi creare, per come l'hai pensato.
Il codice che hai scritto è certamente conforme al proposito di condividere la connessione alla base dati. Renderà più semplice il sistema? Eh eh, domanda da un milione di dollari |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 07:42.



















