Visualizzazione dei risultati da 1 a 9 su 9
  1. #1

    [PILLOLA] Connettersi ed utilizzare un database con iBatis (O/R)

    Ciao,
    questa pillola è rivolta a coloro che hanno un po di esperienza o almeno sanno cosa è un O/R ed in particolare di iBATIS.
    Spero vi piaccia è vi possa essere utilile.

    iBATIS è utilizzabile sia con Java (come qui) che con .NET, vi segnalo il sito ufficiale dove attingere tutti gli approfondimenti del caso: http://ibatis.apache.org .

    La pillola è scompostra in tre parti:
    * Descrittore per la connessione
    * Descrittore delle query
    * Utilizzo all'interno della programmazione



    Descrittore per la connessione
    In questo file verranno specificati i parametri per la connessione al db, e i Descrittori delle query.
    In questo file sono presenti tre sezioni:

    <settings .../> in cui vengono specificati i paramtri di ibatis, come ad esempio il numero di transazioni, il numero di richieste, se abilitare la cache, ed altre proprietà. (Nota tutto quello in questo blocco è opzionale.)

    <transactionManager>...</transactionManager> in questo blocco vengono specificati i parametri per la connessione due parametri importanti sono il tipo di manager per le transazioni:
    * JTA
    * JDBC

    Nel caso si utilizzi JDBC come manager è possibile utilizzare diversi datasource

    * SIMPLE - utilizza l'implementazione classica JDBC
    * DBCP - utilizza l'implementazione Database Connection Pooling per la gestione della connessione
    * JNDI - per ottenere il DataSource esternamente.
    <sqlMap.../> specifica la posizione dei file che mappano le query.

    Ecco un esempio che utilizza il JDBC classico per connetersi ad db e che specifica un solo file di query.

    codice:
    file: ibatis-config.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE sqlMapConfig PUBLIC 
    "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
    <sqlMapConfig>
    
        <settings
                cacheModelsEnabled="true"
                maxRequests="32"
                maxSessions="100"
                maxTransactions="100"/>
    
    <transactionManager type="JDBC">
            <dataSource type="SIMPLE">
                <property name="JDBC.Driver"
                        value="org.firebirdsql.jdbc.FBDriver"/>
                <property name="JDBC.ConnectionURL"
      value="jdbc:firebirdsql:localhost/3050:d:\galleria.FDB"/>
                <property name="JDBC.Username" value="sysdba"/>
                <property name="JDBC.Password" value="masterkey"/>
            </dataSource>
    
        </transactionManager>
        <sqlMap resource="ibatis/xml/sqlmap/immagine.xml"/>
    </sqlMapConfig>
    Come vedete nel caso classico è necessario specificare il Driver, url di connessione, username, password; stessi parametri che specifichereste in programmazione.
    Nota il path inserito in resource non è un real path come c:\cartella\cartella2\file, ma è il path di classe come quello utilizzato per gli import package1.pachage2.etc, percui il significato di quello scritto sopra è che il file immagine.xml si trova nel package sqlmap contenuto in xml contenuto in ibatis

    Descrittore delle query
    A questo punto il setup della connessione è pronto, andiamo a vedere come scrivere il descrittore delle query, consideriamo il caso di una base dati per una galleria di immagini, con due tabelle una "Tipo immagine" e l'altra "Immagini", oviamente Immagini avra ID del tipo immagine.
    Consideriamo inoltre queste due classi semplificate che rappresenta le tabelle della base dati:
    codice:
    public class TipoImmagine {
       private int id;
       private String nometipo;
    
       //metodi get and set
    }
    
    public class Immagine {
      private int id;
      private String descrizione;
      private TipoImmagine tipo;
      private String path;
    
      //metodi get and set
    }
    Adesso definiamo le query:
    * estrazione lista di tutte le immagini
    SELECT * from immagini
    * estrazione di un immagine per id
    SELECT * from immagini where id = ?
    * estrazione del tipo per id
    SELECT * from TipoImmagine where id = ?

    In questo file è possibile specificare:
    * il tipo di cache model da utilizzare per le query, è possibile specificarne di diverse per ogni query.
    * in alias simbolico della classe che rappresenta il dato, senza ogni volta fare riferimento a tutta la gerarchia di package
    * il mapping tra campi della tabella e campi della classe per il risultato
    * se necessario fare anche un mapping dei parametri in ingresso (non lo utilizzeremo in quanto per noi e solo un integer quando estraiamo un immagine)
    * tante query quante ci servono (noi utilizzeremo solo dei select... vedere la guida per i dettagli)

    Ecco il file:
    codice:
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE sqlMap PUBLIC
    "-//iBATIS.com//DTD SQL Map 2.0//EN"
         "http://www.ibatis.com/dtd/sql-map-2.dtd">
    
    <sqlMap namespace="Immagini">
        <cacheModel id="cache" type="LRU">
            <flushInterval hours="24"/>
        </cacheModel>
    
        <typeAlias alias="Immagine" type="beans.Immagine"/>
        <typeAlias alias="TipoImmagine" type="beans.TipoImmagine"/>
    
        <resultMap id="rsImmagine" class="Immagine">
            <result property="id" column="id"/>
            <result property="descrizione" column="descrizione"/>
    
    <result property="tipo" column"idtipo" select="getTipoImmagine"/>
     ....
        </resultMap>
        <resultMap id="rsTipoImmagine" class="TipoImmagine">
            <result property="id" column="id"/>
            <result property="nome" column="nome"/>
        </resultMap>
    
    <select id="getListaImmagini" resultMap="rsImmagine">
    select * from immagini
    </select>
    
    <select id="getImmagine" resultMap="rsImmagine"
    parameterClass="java.lang.Integer"
    cacheModel="cache">
    select * from immagini where id = #value#
    </select>
    
    <select id="getTipoImmagine" resultMap="rsTipoImmagine"
    parameterClass="java.lang.Integer"
    cacheModel="cache">
    select * from TipoImmagini where id = #value#
    </select>
    
    </sqlMap>
    Come vedere in prima istanza vengono definiti i vari mapping tra la classe java e la tabella del db, niente di che, molto banale, apparte quella riga in rosso che banalmente significa "per riempire la proprieta tipo chiama il select getTipoImmagine" percui quando noi chiameremo getImmagine, lui prenderà l'id contenuto del la tabella del db (idtipo) ed eseguira la query getTipoImmagine, riempiento in automatico la classe. Percui quello che avrebbe richiesto da parte nostra una query con join e poi di riempiere due classi separate, viene svolto da lui molto prima.

    Per la definizione delle query, in questo caso tutte di select, accettano come parametro un id (equivalente al nome che si usa per chiamarle) il mapping del risultato (noi utilizziamo un resultMap, ma potrebbe anche essere un resultClass="java.util.Map" cosi da avere una mappa come risultato), il mapping dei parametri se necessario, noi utilizziamo un tipo primitivo Integer, ma poteva essere anche un tipo definito dall'utente con un parameterMap infine se necessario viene specificato il cachemodel.
    Per accedere ai valori passati come parametro si utilizza la sintassi #NOMEPARAMETRO# (dove nomeparametro nel caso di un hashmap sarebbe la key, oppure se utilizzata una classe propria, sarebbe il nome dell'attributo), nel caso di singolo parametro prende il nome #value#.

    Utilizzo all'interno della programmazione
    La prima cosa da fare è ottenere un istanza dello SQL DataMapper, ad esempio con questo codice:
    codice:
    public class Ibatis {
    private static final SqlMapClient sqlMap;
    static {
    try {
    String resource = "ibatis-config.xml";
    Reader reader = Resources.getResourceAsReader (resource);
    sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
    } catch (Exception e) {
    
    e.printStackTrace();
    throw new RuntimeException ();
    }
    }
    public static SqlMapClient getInstance () {
    return sqlMap;
    }
    }
    Non mi dilungo nella spiegazione, in quanto non c'e' niente di complicato, credo sia autoesplicativo.

    Vi mostrero tre modi di chiamare una query: per singolo oggetto, per una lista di oggetti, per una lista di oggetti paginata.

    Vediamo come estrarre un singolo oggetto, consideriamo di voler estrarre l'immagine con id 123.
    codice:
    //import dichiarazioni del caso
    SqlMapClient sqlMap = Ibatis.getInstance();
    
    Immagine img;
    img = (Immagine) sqlMap.queryForObject("getImmagine", new Integer(123));
    
    //utilizza img come meglio ti pare:
    System.out.println(img.toString());
    Le poche righe sopra inserite restituiscono un istanza della classe img se è presente nel db, altrimenti null.

    Estrazione di tutta la lista
    codice:
    //import dichiarazioni del caso
    SqlMapClient sqlMap = Ibatis.getInstance();
    
    List imgs;
    imgs = sqlMap.queryForList("getListaImmagini", null);
    
    //utilizza imgs come meglio ti pare:
    Come prima, se ci sono risultati, viene restitutira un istanza di List, altrimenti null.
    In questo caso al metodo viene passato il secondo parametro null perche non esistono parametri in ingresso alla query.

    Vediamo infine il terzo caso, sicuramente il più interessante. Questo metodo permette di gestire la paginazione di liste, cosa molto frequente.
    codice:
    //import dichiarazioni del caso
    SqlMapClient sqlMap = Ibatis.getInstance();
    
    PaginatedList list;
    list = sqlMap.queryForPaginatedList("ListaImmagini", null, 10);
    
    //utilizza list come meglio ti pare:
    Stesso come precedente, null senza risultati altrimenti un istanza di PaginatedList.
    Il terzo parametro passato al metodo specifica quanti elementi inserire per pagina.
    PaginatedList mette a disposizione vari metodi per gestire la paginazione come:
    * gotoPage(int page)
    * isFirstpage()
    * isLastPage()
    * ed altri vedi la javadoc per il dettaglio
    Tutto questo porta evidenti vantaggi in termini di tempo
    Purtroppo non è possibile sapere il numero di pagine create.

    Conclusioni
    Beh siamo alla fine di quello che volevo dirvi. Spero che l'itaGliano e il tutto sia sufficentemente chiaro ed utile per voi.
    I vantaggi di questo approccio credo siano palesi, una modifica ad esempio al dbms in uso non comporta la modifica di classi con relativo rebuild dell'applicazione, ma solamente la modifica di un file di configurazione. Cosi la Logica applicativa non "sentira" nessuna modifica.

    Non dico altro, le conclusioni sono vostre non mie

    Spero vi sia stato utile, per chiarimenti non esitate a chiedere.

  2. #2

    ma nessuno ti ha risposto...

    ma come...????
    nessuno ti ha ancora risposto???

    bene, allora sono il primo a ringraziarti...
    ho già provato HIBERNATE e devo dire che fa veramente schifo!!!!

    devo ancora provare iBatis ma mi sono letto già un sacco di cosette!!!
    ora con la tua pillola sicuramente tutto risulterà più facile... :rollo:

    già che ci sono avrei anche 2 domandine:
    1) posso fargli mappare qualsiasi query giusto??? comprese query con join o altro?
    2) hai avuto modo anche di provare la velocità con e senza mappatura???

    Ciao e grazie ancora.
    Let's your dream came true!

  3. #3
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    23,904

    Moderazione

    Originariamente inviato da ale500
    già che ci sono avrei anche 2 domandine:
    Le risposte alla "pillola" sono riservate ad eventuali proposte di modifica della stessa.

    Se hai domande da porre a riguardo, apri una discussione dedicata.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Homepage | Blog | Delphi Podcast | Altri link...

  4. #4
    Utente di HTML.it L'avatar di bako
    Registrato dal
    Feb 2004
    Messaggi
    1,806
    codice:
    public class Ibatis {
    private static final SqlMapClient sqlMap;
    static {
    try {
    String resource = "ibatis-config.xml";
    Reader reader = Resources.getResourceAsReader (resource);
    sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
    } catch (Exception e) {
    
    e.printStackTrace();
    throw new RuntimeException ();
    }
    }
    public static getInstance () {
    return sqlMap;
    }
    }
    manca il tipo di ritorno. a me da errore, è giusto così o manca?

  5. #5
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,149
    Effettivamente manca il tipo del valore di ritorno:
    codice:
    public static SqlMapClient getInstance () {
    return sqlMap;
    }
    Correggo la pillola.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  6. #6
    Utente di HTML.it L'avatar di bako
    Registrato dal
    Feb 2004
    Messaggi
    1,806
    Originariamente inviato da LeleFT
    Effettivamente manca il tipo del valore di ritorno:
    codice:
    public static SqlMapClient getInstance () {
    return sqlMap;
    }
    Correggo la pillola.


    Ciao.
    anche la guida ufficiale di ibatis sul sito manca del tipo di ritorno.
    mha.

  7. #7
    Utente di HTML.it L'avatar di bako
    Registrato dal
    Feb 2004
    Messaggi
    1,806
    il metodo
    codice:
    queryForPaginatedList
    è deprecato.
    qualcuno sa cosa si usa ora?

  8. #8
    e volendo trasporre l'esempio sotto .NET magari in c#?
    cosa si fa al posto di questo codice?
    codice:
    String resource = "ibatis-config.xml";
    Reader reader = Resources.getResourceAsReader (resource);
    sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
    byeeeezzzzzzzz

  9. #9
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    23,904

    Moderazione

    Originariamente inviato da Merlino666
    e volendo trasporre l'esempio sotto .NET magari in C#?
    Si parla di due "mondi" alquanto differenti. Comunque sia, lo spazio nella discussione della pillola è orientato alla sola correzione della stessa (come è già avvenuto), non all'affrontare problemi specifici o correlati, per cui si deve aprire un'apposita discussione separata.
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Homepage | Blog | Delphi Podcast | Altri link...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2020 vBulletin Solutions, Inc. All rights reserved.