PDA

Visualizza la versione completa : [PILLOLA]: Connettersi ed utilizzare un database con iBatis (O/R)


FreeManX
27-08-2005, 18:11
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.



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:


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:


<?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:


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.


//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


//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.


//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. :cry:

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 :D

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

ale500
02-07-2006, 20:19
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.

alka
03-07-2006, 03:21
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! :ciauz:

bako
18-05-2007, 11:05
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?

LeleFT
18-05-2007, 11:29
Effettivamente manca il tipo del valore di ritorno:


public static SqlMapClient getInstance () {
return sqlMap;
}

Correggo la pillola.


Ciao. :ciauz:

bako
18-05-2007, 11:31
Originariamente inviato da LeleFT
Effettivamente manca il tipo del valore di ritorno:


public static SqlMapClient getInstance () {
return sqlMap;
}

Correggo la pillola.


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

bako
08-12-2007, 11:53
il metodo

queryForPaginatedList
è deprecato.
qualcuno sa cosa si usa ora?

Merlino666
10-12-2007, 14:38
e volendo trasporre l'esempio sotto .NET magari in c#?
cosa si fa al posto di questo codice?


String resource = "ibatis-config.xml";
Reader reader = Resources.getResourceAsReader (resource);
sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);


byeeeezzzzzzzz

alka
15-12-2007, 16:39
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.

Loading