Pricticas de Ingenieria de Sistemas Informiticos

Anuncio
Ingeniería de Sistemas Informáticos
Curso 2002/2003
3UiFWLFDVGH,QJHQLHUtDGH6LVWHPDV,QIRUPiWLFRV
-'%&
2EMHWLYRV
•
•
•
•
•
•
•
•
•
•
•
•
Estudio del API JDBC.
Instalación de un driver JDBC.
Puente JDBC-ODBC.
Definición de una fuente de datos ODBC.
Conexión a una base de datos.
Pool de conexiones.
Consultas.
Consultas preparadas.
Transacciones.
Excepciones y cierre de conexiones.
Ejercicios.
Estrategia DAO.
•
•
•
•
Servidor de servlets y JSP Tomcat versión 3.3.1 (http://jakarta.apache.org/tomcat/)
Documentación del API JDBC 2.1. Dentro de la documentación de J2SE.
Entorno de desarrollo Java (JBuilder, Kawa, ...)
Microsoft Access 2000.
+HUUDPLHQWDV\GRFXPHQWDFLyQ
1RWD: todo este software puede ser descargado de la página de la asignatura
http://www.dis.um.es/~marcos/isi
(VWXGLRGHO$3,-'%&
El API JDBC define un conjunto de clases e interfaces que nos permiten acceder a cualquier
base de datos relacional con LQGHSHQGHQFLD GHO VLVWHPD JHVWRU (Oracle, MySQL, Informix,
etc.). La versión más reciente del API es la 2.1. Las clases y la documentación de este API van
integradas dentro del entorno SDK de Sun. Las clases de este API se definen dentro del paquete
MDYDVTO. De entre todas las clases destacamos 'ULYHU0DQDJHU &RQQHFWLRQ 6WDWHPHQW
3UHSDUHG6WDWHPHQWy 5HVXOW6HW Comenzaremos la práctica familiarizándonos con estas clases.
,QVWDODFLyQGHXQGULYHU-'%&
Las clases e interfaces para trabajar con una base de datos relacional quedan establecidas por el
API JDBC. Algunas de estas clases están parcialmente diferidas y los interfaces están sin
implementar. Es responsabilidad de cada sistema gestor la implementación de las clases que dan
acceso a las bases de datos. Por lo tanto, para cada tipo de base de datos trabajaremos con un
conjunto diferente de clases. Esto es lo que se denomina GULYHU-'%&.
La instalación de un driver en una aplicación Java se realiza en dos pasos. En primer lugar, se
añaden las clases del driver al FODVVSDWKde la aplicación. A continuación, dentro del código se
FDUJDHOGULYHU antes de acceder a la base de datos:
1
Ingeniería de Sistemas Informáticos
Curso 2002/2003
Class.forName("oracle.jdbc.driver.OracleDriver");
Podremos cargar tantos drivers JDBC como necesitemos en una aplicación Java. Para cada tipo
de sistema gestor utilizaremos una cadena distinta. Por ejemplo, para el GULYHU-'%&2'%& se
utiliza la cadena “VXQMGEFRGEF-GEF2GEF'ULYHU”.
Cada sistema gestor incluye una librería con las clases que implementan el API. Por ejemplo,
Oracle incluye la librería “FODVVHV]LS”. Algunos sistemas requieren del uso de código
nativo. Éste es el caso de Oracle que incluye las librerías dinámicas “ocijdbc8.dll”.
3XHQWH-'%&2'%&
2'%& (2SHQ 'DWD%DVH &RQQHFWLYLW\) es un API Windows que ofrece un acceso uniforme a
cualquier tipo de base de datos relacional cuyo driver se encuentre instalado en el sistema
operativo. El SXHQWH -'%&2'%& es un driver que da acceso a bases de datos ODBC. Este
driver está incorporado dentro de la distribución de Java, por lo que QR HV QHFHVDULR
LQFRUSRUDUORH[SOtFLWDPHQWHHQHOFODVVSDWK de una aplicación Java.
En esta práctica trabajaremos con una base de datos en Access 2000 utilizando un acceso
ODBC. A continuación se describen los pasos para instalar esta base de datos en ODBC.
'HILQLFLyQGHODEDVHGHGDWRV
Para conseguir que nuestra aplicación sea portable entre sistemas gestores de bases de datos
debemos definirla utilizando las VHQWHQFLDV''/GH64/. En nuestro ejemplo definiremos una
sencilla tabla para los clientes de la aplicación:
CREATE TABLE Cliente (
nombre VARCHAR(128) not null,
nif VARCHAR(9) not null,
correo VARCHAR(128) not null,
usuario VARCHAR(128) not null,
clave VARCHAR(56) not null,
CONSTRAINT clave_primaria PRIMARY KEY
CONSTRAINT nif_unico UNIQUE (nif)
);
(usuario),
&UHDFLyQGHODEDVHGHGDWRVHQ$FFHVV
Access 2000 ofrece una serie de asistentes y tipos propios para crear una base de datos.
Deberemos HYLWDU KDFHU XVR GH HVWDV FDUDFWHUtVWLFDV HVSHFtILFDV GH $FFHVV. Utilizaremos el
mecanismo de consultas para crear una base de datos en SQL.
En primer lugar FUHDPRVXQDEDVHGHGDWRV en blanco con nombre “isi”. Accedemos al menú
Insertar/Consulta para definir la tabla en SQL y seleccionamos la vista de diseño.
Seguidamente, cerramos la ventana “Mostrar tabla” y nos quedamos en la ventana “Consulta de
selección”. Nos situamos dentro de la zona gris de la ventana y accedemos al menú de contexto
“9LVWD64/”.
2
Ingeniería de Sistemas Informáticos
Curso 2002/2003
En este modo de definición de consultas podemos escribir sentencias de creación DDL.
Introducimos la definición de la tabla anterior y ejecutamos el comando &RQVXOWD(MHFXWDU. En
este momento ya tenemos definida la tabla. Guardamos la base de datos y cerramos la
aplicación.
'HILQLFLyQGHXQDIXHQWHGHGDWRV2'%&
Dependiendo de la versión de Windows con la que trabajemos, el programa de definición de
fuentes de datos ODBC puede variar de localización, pero siempre dentro del 3DQHOGH&RQWURO
o algún subgrupo. El nombre del programa es “Fuentes de datos ODBC”.
Dentro de la pestaña “'61GHXVXDULR” encontramos los diferentes drivers ODBC instalados en
el sistema.
3
Ingeniería de Sistemas Informáticos
Curso 2002/2003
+DFHPRVXQGREOHFOLFVREUHHOGULYHU³06 Access 'DWDEDVH”. A continuación debemos indicar
el nombre de la base de datos en ODBC y su ruta. Le daremos el nombre “isi”.
&RQH[LyQDXQDEDVHGHGDWRV
Una vez instalado el driver y cargado dentro del código Java sólo necesitamos una conexión a la
base de datos para comenzar a trabajar con ella. La clase 'ULYHU0DQDJHU define el método
JHW&RQQHFWLRQ para crear una conexión a una base de datos. Este método toma como parámetro
una URL JDBC donde se indica el sistema gestor y la base de datos. Opcionalmente, y
dependiendo del sistema gestor, habrá que especificar el ORJLQ y SDVVZRUG para la conexión.
4
Ingeniería de Sistemas Informáticos
Curso 2002/2003
Una URL JDBC tiene la siguiente estructura:
MGEFVJEGSURWRFROREG
donde VJEG indica el nombre del sistema gestor, SURWRFROR el tipo de protocolo dentro del
sistema gestor y EG el nombre de la base de datos. En el caso de JDBC-ODBC la cadena de
conexión sería “MGEFRGEFLVL”, en la que no es necesario establecer el protocolo.
Finalmente, el código para establecer una conexión quedaría del siguiente modo:
Connection con = DriverManager.getConnection("jdbc:odbc:isi");
3RROGHFRQH[LRQHV
En las aplicaciones en las que es necesario el acceso concurrente a una base de datos es
necesario GLVSRQHUGHYDULDVFRQH[LRQHV. Éste es el caso de los servlets, que sirven peticiones
concurrentes del servidor web. El proceso de creación y destrucción de una conexión a una base
de datos es costoso e influye sensiblemente en el rendimiento de una aplicación.
La estrategia más utilizada en este tipo de aplicaciones es el uso de un SRRO de conexiones. Un
pool es un conjunto de conexiones disponibles para ser utilizadas. Cuando un servlet necesite
realizar una consulta, solicita una conexión al pool y cuando termine de utilizar la base de datos,
devolverá la conexión. Algunos drivers manejan internamente un pool de conexiones
proporcionando un objeto 'DWD6RXUFH. Estos objetos son servidos por el contenedor. En lugar
de definir un DataSource para el contenedor Tomcat utilizaremos un pool de conexiones
siguiendo la estrategia vista en clase.
&RQVXOWDV
Las consultas sobre una base de datos se realizan utilizando objetos de las clases 6WDWHPHQW y
3UHSDUHG6WDWHPHQW. Estos objetos son creados a partir de una conexión.
Statement stmt = con.createStatement();
La clase 6WDWHPHQW contiene los métodos H[HFXWH4XHU\ y H[HFXWH8SGDWH para realizar consultas
y actualizaciones, respectivamente. Ambos métodos soportan consultas en SQL-92.
ResultSet rs = stmt.executeQuery("SELECT * from Cliente");
El método H[HFXWH4XHU\ devuelve un objeto 5HVXOW6HW para poder recorrer el resultado de la
consulta utilizando un cursor.
while (rs.next()) {
String usuario = rs.getString("usuario");
}
5
Ingeniería de Sistemas Informáticos
Curso 2002/2003
El método QH[W es utilizado para hacer avanzar el cursor. Para recuperar una columna del
registro utilizamos los métodos JHW. Hay un método JHW para cada tipo básico Java y para las
cadenas. Dependiendo del tipo de las columnas podremos utilizar uno u otro.
Otro método interesante del cursor es ZDV1XOO que nos informa si el último valor leído con un
método JHW fue nulo.
7LSRGHGDWR64/
CHAR
VARCHAR
LONGVARCHAR
NUMERIC
DECIMAL
BIT
TINYINT
SMALLINT
INTEGER
BIGINT
REAL
FLOAT
DOUBLE
BINARY
VARBINARY
DATE
TIME
TIMESTAMP
0pWRGR
String getString()
String getString()
InputStream
getAsciiStream() ó
getUnicodeString()
java.math.BigDecimal
getBigDecimal()
java.math.BigDecimal
getBigDecimal()
boolean getBoolean()
byte getByte()
short getShort()
int getInt()
long getLong()
float getFloat()
double getDouble()
double getDouble()
byte[] getBytes()
InputStream
getBinayStream()
java.sql.Date getDate()
java.sql.Time getTime()
java.sql.getTimestamp
getTimeStamp()
Podemos llamar a los métodos JHW utilizando el nombre de la columna (esto no siempre puede
ser determinado) o la posición en la consulta. Lo más práctico y legible es utilizar el nombre de
la columna, dejando el uso del acceso por posición cuando el valor de la columna no tenga
ningún nombre, como por ejemplo con un campo calculado.
Las consultas de actualización, H[HFXWH8SGDWH, devuelven el número de registros insertados,
registros actualizados o eliminados, dependiendo del tipo de consulta que se trate.
6
Ingeniería de Sistemas Informáticos
Curso 2002/2003
&RQVXOWDVSUHSDUDGDV
Las consultas preparadas están representadas por la clase 3UHSDUHG6WDWHPHQW. Representan
consultas SUHFRPSLODGDV que pueden tener parámetros. Se instancia del siguiente modo:
PreparedStatement pstmt = con.preparedStatement("SELECT * from Cliente");
PreparedStatement pstmt = con.preparedStatement("SELECT * from Cliente WHERE
usuario = ? ");
Para las consultas que han de realizarse muy a menudo es PiVHILFLHQWH utilizar una consulta
preparada, siendo la única opción cuando la consulta tiene parámetros. Los SDUiPHWURV se
expresan con el carácter ‘?’.
Establecemos los parámetros de una consulta utilizando métodos VHW que dependen del tipo SQL
de la columna (ver tabla).
pstmt.setString(1, "Marcos");
El primer argumento de este método es la posición del parámetro dentro de la consulta.
Finalmente, ejecutamos la consulta utilizando el método H[HFXWH4XHU\ o H[HFXWH8SGDWH,
ambos sin parámetros, dependiendo del tipo de consulta. Si la consulta tenía parámetros, en este
momento quedarán vacíos.
7UDQVDFFLRQHV
Por defecto, con una conexión trabajamos HQ PRGR DXWRFRPPLW con valor WUXH. Esto quiere
decir que cada consulta es una transacción en la base de datos. Si queremos definir una
transacción estableceremos el modo DXWRFRPPLW a IDOVH con el método VHW$XWR&RPPLW de la
clase &RQQHFWLRQ.
En modo no DXWRFRPPLW las transacciones quedan definidas por las ejecuciones de los métodos
FRPPLW y UROOEDFN. Una transacción abarca desde el último FRPPLWo UROOEDFN hasta siguiente
FRPPLW. Los métodos FRPPLW o UROOEDFN forman parte de la clase &RQQHFWLRQ.
([FHSFLRQHV\FLHUUHGHFRQH[LRQHV
Todas las acciones sobre una base de datos pueden lanzar la excepción genérica 64/([FHSWLRQ.
Por lo tanto, ha de tenerse en cuenta que esta excepción debe ser capturada siempre que
trabajemos con una base de datos.
Para terminar, destacar que las conexiones con una base de datos consumen muchos recursos en
el sistema gestor y conviene cerrarlas con el método FORVH siempre que vayan a dejar de ser
utilizados, en lugar de esperar a que el JDUEDJHFROOHFWRUde Java las elimine.
También conviene cerrar las consultas (6WDWHPHQW y 3UHSDUHG6WDWHPHQW) y los resultados
(5HVXOW6HW) para liberar los recursos.
7
Ingeniería de Sistemas Informáticos
Curso 2002/2003
(MHUFLFLRV
Modifica el ejercicio de los VHUYOHWV para que los usuarios sean almacenados en una base de
datos. Los pasos a realizar serán los siguientes:
•
Instancia un pool de conexiones y almacénalo en la aplicación web. Esta acción la
realizarán los dos servlets dentro del método LQLW. Nótese que para que la aplicación sea
totalmente portable e independiente del sistema donde sea instalada tanto la cadena de
conexión como el driver deberían ser especificados como parámetros de la aplicación
web.
private DataSource ds;
...
public void init(ServletConfig config) throws SQLException {
...
ServletContext app = config.getServletContext();
this.ds = (DataSource) app.getAttribute("DataSource");
if ( this.ds == null ) {
try {
this.ds = ConnectionPool.getInstance("jdbc:odbc:isi", "", "");
app.setAttribute("DataSource", ds);
} catch (Exception e) {
e.printStackTrace();
}
}
}
...
•
Utiliza una consulta normal para insertar el cliente en la base de datos (6HUYOHW5HJLVWUR).
Sustituimos el código que creaba el EHDQy lo insertaba en la tabla hash por una consulta
SQL.
boolean error = false;
String mensajeError = "";
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
con = ds.getConnection();
stmt = con.createStatement();
// Consulta si hay un Cliente con el mismo nombre de usuario
rs = stmt.executeQuery("SELECT * FROM Cliente WHERE usuario = ’" +
peticion.getParameter("usuario") + "’");
if ( rs.next() ) { // Existe un usuario
error = true;
mensajeError = "Usuario duplicado";
// Obtiene la URL precedente
String referer = peticion.getHeader("referer");
// Establece la cabecera de refresco
respuesta.setHeader("refresh", "3; URL=" + referer);
} else {
stmt.executeUpdate("INSERT into Cliente values ("
+ "’" + peticion.getParameter("nombre") + "’,"
+ "’" + peticion.getParameter("nif") + "’,"
+ "’" + peticion.getParameter("correo") + "’,"
+ "’" + peticion.getParameter("usuario") + "’,"
8
Ingeniería de Sistemas Informáticos
Curso 2002/2003
+ "’" + peticion.getParameter("clave") + "’"
+ ")");
} catch (SQLException e) {
error = true;
mensajeError = "Error al insertar el cliente en la base de datos";
}
}
stmt.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
error = true;
mensajeError = "Error en la base de datos";
}
...
// Nuestros datos
if (!error) {
out.println("<B><P> Datos Cliente Procesados </P> </B>");
out.println("<B><P> Autor: " + autor + "</P></B>");
} else {
out.println("<H1> Error: " + mensajeError + " </H1>");
}
•
Utiliza una consulta preparada dentro del servlet de identificación (6HUYOHW/RJLQ) para
comprobar la existencia de un usuario. Dado que sólo es necesario crearla una vez, la
instanciamos dentro del método LQLW
private PreparedStatement recuperaUsuario;
public void init(ServletConfig config) {
«
try {
Connection con = ds.getConnection();
recuperaUsuario = con.prepareStatement(" SELECT * FROM Cliente WHERE
usuario = ?");
} catch (SQLException e) {
e.printStackTrace();
}
}
Dentro del método GR3RVW de 6HUYOHW/RJLQ el acceso a ella será sincronizado (bloque
V\QFKURQL]HG) para garantizar un funcionamiento WKUHDGVDIHya que la consulta es un recurso
compartido en el entorno concurrente de las peticiones a un servlet. Sustituimos el código que
trabaja con la tabla hash por la consulta.
9
Ingeniería de Sistemas Informáticos
Curso 2002/2003
// Obtenemos la información de la petición
String usuario = peticion.getParameter("usuario");
String clave = peticion.getParameter("clave");
Cliente c = null;
try {
// Realizamos la consulta
synchronized (recuperaUsuario) {
// Establece el parámetro de la consulta
recuperaUsuario.setString(1, usuario);
ResultSet rs = recuperaUsuario.executeQuery();
if ( rs.next() ) { // El usuario existe
String claveUsuario = rs.getString("clave");
if (claveUsuario.equals(clave)) {
identificado = true;
// Crea el bean usuario
c = new Cliente();
c.setNombre(rs.getString("nombre"));
c.setNif(rs.getString("nif"));
c.setCorreo(rs.getString("correo"));
c.setUsuario(rs.getString("usuario"));
c.setClave(claveUsuario);
}else
identificado = false;
} else
identificado = false;
}
} catch (Exception e) {
e.printStackTrace();
respuesta.sendError(500, "Error en la base de datos");
}
...
(VWUDWHJLD'$2
Si observamos detenidamente los servlets creados en esta práctica y en la anterior podremos
apreciar que el código encargado de almacenar la información (clientes) está disperso a través
de todo el servlet. Un cambio en el mecanismo de persistencia como el que hemos realizado en
esta práctica al pasar del almacenamiento en una tabla KDVK a una base de datos es costoso
incluso para servlets tan sencillos como con los que estamos trabajando. Para evitar estos
inconvenientes lo recomendable siempre es utilizar el patrón de diseño DAO para que nuestra
aplicación sea tolerante a los cambios en el almacenamiento.
El patrón de diseño DAO define un modo de acceder a los datos de una aplicación con
independencia del tipo de almacenamiento, encapsulando todos los detalles de acceso a los
recursos de datos en unas clases llamadas 'DWD$FFHVV2EMHFWV. En lo que resta de este apartado
seguiremos la estrategia DAO vista en clase. En primer lugar crearemos una IDFWRUtDDEVWUDFWD
de objetos DAO que llamaremos '$2)DFWRULD, que en nuestro caso sólo tendrá un método
factoría para generar los DAO acceso a los datos de los clientes.
10
Ingeniería de Sistemas Informáticos
Curso 2002/2003
// Define una factoría abstracta que devuelve todos los DAO de la aplicación
public abstract class DAOFactoria
{
// Métodos factoría
public abstract ClienteDAO getClienteDAO();
// Declaración como constantes de los tipos de factoría
public final static int ACCESS = 1;
public static DAOFactoria getDAOFactoria (int tipo) throws DAOException
{
switch(tipo) {
case ACCESS: {
try {
return new AccessDAOFactoria();
} catch (Exception e) {
throw new DAOException(e.getMessage());
}
} default:
return null;
}
}
}
A continuación creamos tantas IDFWRUtDV FRQFUHWDV como tipos de almacenamiento diferentes
tengamos. En esta práctica hemos hecho uso de una base de datos $FFHVV, aunque no hemos
utilizado características especiales de la misma. A modo de ejemplo, crearemos una factoría
concreta para este sistema gestor. Esta factoría utiliza un SRROde conexiones. Por simplicidad se
codifica la información de acceso a la base de datos, aunque lo ideal sería recuperarla desde un
fichero de propiedades.
import javax.sql.*;
// Factoría DAO Access que implementa la factoría abstracta
public class AccessDAOFactoria extends DAOFactoria
{
DataSource ds;
public AccessDAOFactoria ()
throws DAOException, ClassNotFoundException, java.sql.SQLException {
ds = ConnectionPool.getInstance("jdbc:odbc:isi", "", "");
}
public ClienteDAO getClienteDAO() {
return (ClienteDAO) new AccessClienteDAO(ds);
}
}
El DAO para acceder a los datos de los clientes viene definido por una LQWHUID]'$2 donde se
encuentran recogidos los métodos necesarios para el acceso a los datos. En nuestra aplicación
sólo necesitamos un método de creación, un método de búsqueda por usuario, un método que
para obtener todos los clientes y un método de actualización (práctica siguiente).
11
Ingeniería de Sistemas Informáticos
Curso 2002/2003
// Define los métodos de acceso a los datos para un cliente
public interface ClienteDAO
{
public Cliente createCliente(String nombre, String nif, String correo,
String usuario, String clave) throws DAOException;
// Busca un Cliente por "usuario" (clave primaria). Si no lo encuentra
// devuelve "null"
public Cliente findClienteByUsuario(String usuario) throws DAOException;
// Obtiene todos los clientes
public java.util.Collection findAll() throws DAOException;
// Actualiza un cliente
public void update (Cliente c) throws DAOException;
}
Seguidamente creamos una '$2FRQFUHWR para Access (en general para SQL) que implemente
la interface DAO del cliente. Estos objetos serán los que sean devueltos por la factoría concreta.
import java.sql.*;
import javax.sql.*;
import java.util.*;
public class AccessClienteDAO implements ClienteDAO
{
private DataSource ds;
public AccessClienteDAO (DataSource ds) {
this.ds = ds;
}
public Collection findAll() throws DAOException {
LinkedList clientes = new LinkedList();
Connection con = null;
try {
con = ds.getConnection();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM Cliente ");
while (rs.next()) {
Cliente c = new Cliente();
c.setNombre(rs.getString("nombre"));
c.setNif(rs.getString("nif"));
c.setCorreo(rs.getString("correo"));
c.setUsuario(rs.getString("usuario"));
c.setClave(rs.getString("clave"));
clientes.add(c);
}
rs.close(); stmt.close();
con.close();
return clientes;
} catch (SQLException e) {
throw new DAOException(e.getMessage());
}
}
12
Ingeniería de Sistemas Informáticos
Curso 2002/2003
public void update (Cliente c) throws DAOException{
Connection con = null;
try {
con = ds.getConnection();
String usuario = c.getUsuario();
Statement stmt = con.createStatement();
stmt.executeUpdate(
"UPDATE Cliente SET "
+ "nombre = ’" + c.getNombre() + "’ , "
+ "nif = ’" + c.getNif() + "’ , "
+ "correo = ’" + c.getCorreo() + "’ , "
+ "clave = ’" + c.getClave() + "’ "
+ "WHERE usuario = ’" + c.getUsuario() + "’");
stmt.close();
con.close();
} catch (SQLException e) {
throw new DAOException(e.getMessage());
}
}
// Inserta el cliente en la base de datos y crea un JavaBean con
// los valores
public Cliente createCliente(String nombre, String nif, String correo,
String usuario, String clave)
throws DAOException
{
Ejercicio
}
public Cliente findClienteByUsuario(String usuario)
throws DAOException
{
}
Ejercicio
}
Todos los métodos de acceso a datos que utilizan un DAO potencialmente pueden lanzar la
excepción '$2([FHSWLRQ:
public class DAOException extends Exception {
public DAOException (String msg) {
super(msg);
}
}
Por último, PRGLILFDUHPRVORVVHUYOHWV para que hagan uso de la estrategia DAO. En el método
LQLW, en lugar de crear y registrar un pool de conexiones lo que hará será obtener una factoría
DAO para $FFHVV.
13
Ingeniería de Sistemas Informáticos
Curso 2002/2003
DAOFactoria daoFactoria;
...
public void init(ServletConfig config) {
super.init(config);
// Obtiene el objeto aplicación
ServletContext app = getServletConfig().getServletContext();
// Comprueba si ya existe la factoría en la aplicación
daoFactoria = (DAOFactoria) app.getAttribute("DAOFactoria");
if (daoFactoria == null) {
// Instancia la factoría concreta ACCESS utilizando la
// factoría abstracta
daoFactoria = DAOFactoria.getDAOFactoria(DAOFactoria.ACCESS);
// La almacena en la aplicación web
app.setAttribute("DAOFactoria", daoFactoria);
}
}
Con el código anterior conseguimos que los servlets de nuestra aplicación dispongan de la
factoría de DAOs almacenados en un atributo y disponible en el método GR*HW y GR3RVW, y a la
vez que esa factoría se comparta en toda la aplicación. Siempre que necesitamos trabajar con
objetos cliente, obtenemos el DAO concreto para el tipo Cliente y trabajamos con él:
ClienteDAO clienteDAO = daoFactoria.getClienteDAO();
// Comprueba si existe un determinado usuario registrado
Cliente c = clienteDAO.findClienteByUsuario(usuario);
if (c != null) ...
// Actualiza los datos del cliente
clienteDAO.update(c);
...
// Inserta un nuevo cliente en la aplicación
clienteDAO.createCliente(...);
14
Ingeniería de Sistemas Informáticos
Curso 2002/2003
(MHUFLFLRDOWHUQDWLYR
El ejercicio alternativo a esta práctica consiste en implementar una estrategia de acceso a datos
DAO para el tipo de datos 3URGXFWR. Un producto tiene como información el nombre, el tipo de
producto, su precio, un indicativo de si está en oferta y un identificador único que será asignado
automáticamente.
Los pasos para implementar esta estrategia son los siguientes:
• Crea un JavaBean 3URGXFWR con toda la información del producto (9DOXH2EMHFW).
• Define la interfaz '$23URGXFWR con métodos para manejar los productos: crear un
producto, eliminarlo, actualizarlo (sincroniza los datos con una instancia), obtener un
producto por identificador, obtener todos los productos de una categoría y un último método
de consulta de todos los productos.
• Crea una factoría abstracta de DAOs que tenga un método para conseguir un '$23URGXFWR.
• Definimos un DAO que almacene los datos en una base de datos $FFHVV:
o Creamos una nueva base de datos en $FFHVV y definimos la tabla en SQL.
o Registramos la base de datos en ODBC.
o Creamos el DAO que implemente la interfaz '$23URGXFWR utilizando un pool de
conexiones sobre esta base de datos.
• Por último, creamos la factoría DAO concreta para el almacenamiento en $FFHVV.
Para probar el funcionamiento de la estrategia DAO crearemos un programa que haga uso del
mismo: creará unos cuantos productos, los actualizará, los eliminará, hará consultas, etc. para
comprobar que el funcionamiento es correcto.
15
Descargar