2008-11-18 16 views
13

Per implementare il codice di accesso ai dati nella nostra applicazione abbiamo bisogno di un framework per avvolgere jdbc (l'ORM non è la nostra scelta, a causa della scalabilità).semplice wrapper jdbc

Il framework più bello con cui ho lavorato è Spring-Jdbc. Tuttavia, la politica della mia azienda è di evitare dipendenze esterne, in particolare Spring, J2EE, ecc. Quindi stiamo pensando di scrivere il proprio framework jdbc fatto a mano, con funzionalità simili Spring-jdbc: mappatura delle righe, gestione degli errori, funzionalità di supporto di java5, ma senza supporto per le transazioni.

Qualcuno ha esperienza di scrittura di tale framework wrapper jdbc? Se qualcuno ha esperienza nell'utilizzo di altri framework wrapper jdbc, si prega di condividere la vostra esperienza.

Grazie in anticipo.

+10

"la politica della mia azienda è di evitare le dipendenze esterne, in particolare la primavera, J2EE, ecc." wow, sembra un incubo. Sembra un ciclo infinito di re-inventare la ruota –

+7

J2EE è una "dipendenza esterna" ?? – yegor256

+0

Se stai cercando un'esecuzione SQL semplicistica per la mappatura degli oggetti, mybatis è un'opzione. Non lo chiamerei un ORM nel senso che non fa grafici oggetto come farebbe ibernare. Semplicemente ti permette di eseguire sql e inserire parametri dal tuo input o mappare le colonne agli oggetti di output. – Matt

risposta

13

Abbiamo scritto il nostro involucro. Questo argomento è degno di una carta, ma dubito che avrò mai tempo per scrivere, quindi ecco alcuni punti chiave:

  • abbiamo abbracciato sql e fatto alcun tentativo di nasconderlo. l'unica modifica è stata l'aggiunta del supporto per i parametri denominati. i parametri sono importanti perché non incoraggiamo l'uso di SQL al volo (per ragioni di sicurezza) e usiamo sempre PreparedStatements.

  • per la gestione delle connessioni, abbiamo utilizzato Apache DBCP. All'epoca era comodo, ma non è chiaro quanto sia necessario con le moderne implementazioni JDBC (mancano i documenti su questa roba). DBCP raggruppa anche PreparedStatements.

  • non ci siamo preoccupati della mappatura delle righe. invece (per le query) abbiamo usato qualcosa di simile a ResultSetHandler di dbutil di Apache, che consente di "alimentare" il set di risultati in un metodo che può quindi riversare le informazioni ovunque si desideri. Questo è più flessibile e, in effetti, non sarebbe difficile implementare un ResultSetHandler per il mapping delle righe. per inserti/aggiornamenti abbiamo creato una generica classe di record (fondamentalmente una hashmap con alcuni campanelli e fischietti extra). il problema più grande con la mappatura delle righe (per noi) è che sei bloccato non appena fai una query "interessante" perché potresti avere campi che si associano a classi diverse; perché potresti avere una struttura gerarchica di classi ma un set di risultati piatto; o perché la mappatura è complessa e dipende dai dati.

  • abbiamo costruito nella registrazione degli errori. per la gestione delle eccezioni: su una query intercettiamo e registriamo, ma per un aggiornamento intercettiamo, registriamo e ripassiamo un'eccezione non controllata.

  • abbiamo fornito il supporto delle transazioni utilizzando un approccio wrapper. il chiamante fornisce il codice che esegue la transazione e ci assicuriamo che la transazione sia gestita correttamente, senza alcuna possibilità di dimenticare di completare la transazione e con il rollback e la gestione degli errori integrata.

  • in seguito, abbiamo aggiunto uno schema di relazione molto semplicistico che consente a un singolo aggiornamento/inserto di applicare a un record e tutte le sue dipendenze. per semplificare le cose, non l'abbiamo usato sulle query e abbiamo deciso in particolare di non supportare questo con le eliminazioni perché è più affidabile utilizzare le eliminazioni a cascata.

Questo involucro è stato utilizzato con successo in due progetti fino ad oggi. È, ovviamente, leggero, ma in questi giorni tutti dicono che il loro codice è leggero. Ancora più importante, aumenta la produttività del programmatore, diminuisce il numero di bug (e rende più facile rintracciare i problemi) ed è relativamente facile da rintracciare, se necessario, perché non crediamo nell'aggiunta di molti livelli solo per fornire una bella architettura.

5

Spring-JDBC è fantastico. Considera che per un progetto open source come Spring il lato negativo della dipendenza esterna è ridotto al minimo. Puoi adottare la versione più stabile di Spring che soddisfi i requisiti di astrazione JDBC e sai che sarai sempre in grado di modificare il codice sorgente se ti imbatterai in un problema, senza dipendere da una parte esterna. È anche possibile esaminare l'implementazione per eventuali problemi di sicurezza che la propria organizzazione potrebbe avere con codice scritto da una parte esterna.

1

Prova JdbcSession da jcabi-jdbc. È semplice come dovrebbe essere JDBC, ad esempio:

String name = new JdbcSession(source) 
    .sql("SELECT name FROM foo WHERE id = ?") 
    .set(123) 
    .select(new SingleOutcome<String>(String.class)); 

Questo è tutto.

1

Questa sembra una decisione molto miope. Considera il costo di sviluppo/mantenimento di un simile framework, specialmente quando è possibile ottenerlo e il suo codice sorgente è gratuito. Non solo non devi fare da solo lo sviluppo, puoi modificarlo a piacere se necessario.

Detto questo, quello che devi veramente duplicare è la nozione di JdbcTemplate e le sue callback (PreparedStatementCreator, PreparedStatementCallback), nonché RowMapper/RowCallbackHandler. Non dovrebbe essere complicato scrivere qualcosa come questo (specialmente considerando che non devi fare la gestione delle transazioni).

Ovunque, come ho detto, perché scriverlo quando è possibile ottenerlo gratuitamente e modificare il codice sorgente come meglio credi?

2

Quello che preferisco: Dalesbred. È autorizzato dal MIT.

Un semplice esempio di come ottenere tutte le righe per una classe personalizzata (Reparto).

List<Department> departments = db.findAll(Department.class, 
    "select id, name from department"); 

quando la classe personalizzata è definita come:

public final class Department { 
    private final int id; 
    private final String name; 

    public Department(int id, String name) { 
     this.id = id; 
     this.name = name; 
    } 
} 

Esonero di responsabilità: si tratta di una società per cui lavoro.