Oggi esistono molteplici modi per gestire la persistenza in applicazioni J2EE:
- Hibernate
- Entity Bean
- Entity BMP
- DAO con classi POJO
- Spring
- e altro ancora
In questo articolo mi vorrei soffermare su una mia implementazione del pattern DAO.
Problema
Persistere un'entity rispettando i seguenti requisiti:
- indipenenza dal back end (DB2, Oracle, XML, LDAP, Lucene, ecc.);
- possibilità di far partecipare uno o più DAO ad una singola transazione;
- nascondere le eccezioni specifiche di ciascun back end;
- persistere una entità logica e non fisica (qusto implica che un DAO può manipolare una o più tabelle se queste rappresentano un'unica entità logica).
Soluzione
La prima cosa che faccio quando sviluppo applicazioni web è quella di identificare le entità logiche del problema (domain problem). Ad ogni entità associo un DAO che sarà responsabile di tutte le attività di persistenza su quell'entità , es. le operazioni CRUD (CRreate, Update, Delete).
Iniziamo con il definire la nostra entità .
public class EntityValue {
private object primaryKey;
private String property;
Object getPrimaryKey() {
}
public void setPrimaryKey(Object key) {
}
String getProperty() {
}
public void setProperty(String property) {
}
}
A questo punto creiamo un'interfaccia DAO per la nostra entity.
public interface DAOEntity {
Object create(EntityValue entity) throws DAOException;
void update(EntityValue entity) throws DAOException;
void delete(Object key) throws DAOException;
// finders
EntityValue findByPrimaryKey(Object key) throws DAOException;
Collection findAll() throws DAOException;
}
A seconda dei back end che vogliamo supportare implementeremo l'interfaccia DAOEntity. Prima di fare ciò, è necessario definire una factory che, in base ad un parametro di configurazione, instanzia l'implementazione specifica per un dato back end.
public abstract class DAOFactory {
private static final TransactionManager tm; // la classe figlia associerà il transaction manager relativo ad esso
public static DAOFactory makeFactory() {
// leggi da file di configurazione il back end desiderato (DB2, MySQL, Oracle, XML, ecc.).
}
public abstract DAOEntity getDAOEntity();
// aggiungi qui altri metodi getDAOXXX
public TransactionManager getTransactionManager() {
}
}
A questo punto, per ogni back end, va implementata una classe che estende DAOFactory e implementa i metodi astratti.
Vediamo ora un'ipotetica implementazione di DAO entity nell'ipotesi che il back end sia DB2. In particolare vedremo l'implementazione della create, le altre sono più o meno simili.
public class DB2DAOEntity imlements DAOEntity {
private static final String SQL_CREATE="INSERT INTO ....";
private static final String SQL_UPDATE="UPDATE ....";
private static final String SQL_DELETE="DELETE ....";
// finders
private static final String SQL_FIND_BY_PRIMARY_KEY="SELECT ... FROM ... WHERE KEY=?";
private static final String SQL_FIND_ALL ="SELECT ... FROM ...";
Object create(EntityValue entity) throws DAOException {
DB2Transaction tx = (DB2Transaction) DAOFactory.makeFactory.getTransactionManager().getTransaction();
Connection conn = tx.getConnection();
PreparedStatement stmt = null;
try {
entity.setPrimeryKey(// generate oid);
stmt = conn.prepareStatement(SQL_CREATE);
stmt.setXXX(1, entity.getPrimaryKey());
...
stmt.setXXX(N, entity.getProperty());
stmt.execute();
} catch(SQLException exception) {
} finally {
}
}
void update(EntityValue entity) throws DAOException {
}
void delete(Object key) throws DAOException {
}
// finders
EntityValue findByPrimaryKey(Object key) throws DAOException {
}
Collection findAll() throws DAOException {
}
}
Si osservi come la transazione viene aperta nel business layer e passata al DAO attraverso l'area local al thread (ThreadLocal, vedi articolo Transazioni JDBC). Il DAO gestisce solo statement e result set (quest'ultimo solo nei finders). E' importante l'uso del finally per la chiusura degli statement e result set.
Comments (0)
You don't have permission to comment on this page.