Curso de verano de la Universidad de Málaga. Java y …galvez/cursoVerano/JDBC-Oracle.pdf ·...

112
S G R Curso de verano de la Universidad de Málaga. Java y Bases de Datos (Oracle). Profesores: Sergio Gálvez Rojas Índice Capítulo 1: Introducción. Introducción. Procedimientos almacenados. JDBC. SQLJ. OC4J. JDeveloper. Capítulo 2: Procedimientos almacenados en Java. Procedimientos almacenados en Java. Ejemplo. Paso 1: Codificación. Ejemplo. Paso 2: Carga. Ejemplo. Paso 1: Publicación. Ejemplo. Pasos 4 y 5: Permisos e invocación. loadjava. Consideraciones sobre loadjava. Publicación. Correspondencia entre tipos. Tipos de parámetros. Colecciones e iteradores. Creación de tipos en Oracle. Otras invocaciones. Capítulo 3: Java Database Connectivity. Java Database Connectivity. Cómo acceder a una base de datos. Drivers JDBC de Oracle. Ejemplo preliminar. JDBC 2.0. Importación de paquetes y Carga del driver. Conexión a la base de datos. Consulta a la base de datos. Procesamiento del ResultSet. Cierres. Sentencias preparadas. Ejemplo de sentencia preparada. Acceso a la base de datos en procedimientos almacenados. Acceso a procedimientos almacenados. Ejemplo de llamada a DBMS_OUTPUT. Procesamiento básico de transacciones. Gestión de ResultSet.

Transcript of Curso de verano de la Universidad de Málaga. Java y …galvez/cursoVerano/JDBC-Oracle.pdf ·...

SGR

Curso de verano de la Universidad de Málaga.

Java y Bases de Datos (Oracle).

Profesores: Sergio Gálvez Rojas

Índice

Capítulo 1: Introducción.Introducción.Procedimientos almacenados.JDBC.SQLJ.OC4J.JDeveloper.

Capítulo 2: Procedimientos almacenados en Java.Procedimientos almacenados en Java.Ejemplo. Paso 1: Codificación.Ejemplo. Paso 2: Carga.Ejemplo. Paso 1: Publicación.Ejemplo. Pasos 4 y 5: Permisos e invocación.loadjava.Consideraciones sobre loadjava.Publicación.Correspondencia entre tipos.Tipos de parámetros.Colecciones e iteradores.Creación de tipos en Oracle.Otras invocaciones.

Capítulo 3: Java Database Connectivity.Java Database Connectivity.Cómo acceder a una base de datos.Drivers JDBC de Oracle.Ejemplo preliminar.JDBC 2.0.Importación de paquetes y Carga del driver.Conexión a la base de datos.Consulta a la base de datos.Procesamiento del ResultSet.Cierres.Sentencias preparadas.Ejemplo de sentencia preparada.Acceso a la base de datos en procedimientos almacenados.Acceso a procedimientos almacenados.Ejemplo de llamada a DBMS_OUTPUT.Procesamiento básico de transacciones.Gestión de ResultSet.

ResultSet con scroll.Ejemplo de ResultSet con scroll.ResultSet actualizable.Ejemplo de ResultSet actualizable.Metadatos de ResultSet.Ejemplo de metadatos de ResultSet.Metadatos de la base de datos.Gestión de Large Objects.Ejemplo de escritura de BLOB.Ejemplo de lectura de BLOB.Procesamiento batch.

Capítulo 4: SQLJ.SQLJ.Ejecución de un fichero SQLJ.Declaraciones SQLJ.Establecimiento de la conexión.Primer programa.SELECT con resultado simple.SELECT con resultado múltiple.Ejemplo de SELECT con resultado múltiple.Iteradores scrollable.Ejemplo de iteradores scrollable.Ejemplo con scrollable anónimo.Sensibilidad y control de transacciones.DDL y DML.Cursores anidados.Ejemplo de cursores anidados.Procedimientos PL/SQL.SQLJ dentro de procedimientos PL/SQL.VARRAY.Consultas a VARRAY.Inserción en VARRAY.

Capítulo 5: JDeveloper.JDeveloper.Instalación.Ejecución.Filosofía estructural.Ejecución de un proyecto.Deposición.Caso práctico.Pasos (I).Pasos (II).Pasos (III).Pasos (IV).Pasos (V).JPublisher.Filosofía OC4J.Capa de negocio.

SGR

Capa de manipulación.Creación de una aplicación OC4J.Módulo de aplicación OC4J.Test básico de un módulo de aplicación OC4J.Creación de un cliente.Ejecución de un proyecto.Deposiciones d euna aplicación OC4J.El servidor J2EE.Deposición en forma de Enterprise JavaBeans.Deposición en JSP.Propiedades de un objeto entidad.Propiedades de un objeto vista.Creación de un cliente manualmente.Cómo conectar con un módulo de aplicaciones.Búsqueda del módulo de aplicaciones y obtención de la vista.Acceso a la vista.Creación de la aplicación completa.La clase ViewObjectImpl.La clase ViewObjectImpl y la cláusula WHERE.La clase Row y la gestión de transacciones.Obtención de un BLOB.Escritura de un BLOB.

Capítulo 1: Introducción.

Capítulo 1 Introducción

p Hay varias formas de interactuar con una base dedatos:

p Procedimiento almacenado. Propio de cada SGBD(Sistema Gestor de Bases de Datos).

p JDBC (Java Database Connectivity). Estándar. Yampliamente extendido.

p SQLJ (SQL para Java). Estándar pero nototalmente extendido.

p OC4J (Oracle Components for Java). No estándarpero de una gran versatilidad.

p Para todo esto utilizaremos Jdeveloper, que es unentorno de desarrollo para Oracle. Pero antes deempezar con Jdeveloper es bueno saber trabajar conlas tecnoilogías correspondientes sin necesidad deentorno.

Capítulo 1: Introducción.

Procedimientos almacenadosp Un procedimiento almacenado en Java (PAJ) es unmétodo Java convenientemente publicado yalmacenado en la base de datos.

p Requiere una especificación de llamada queestablece una correspondencia entre:

< Nombre de método Java y el nombre en SQL.< Tipos de los parámetros en Java y los correspondientes en

SQL.< Tipo del valor retornado en Java y el que corresponda en SQL.

p Un PROCEDURE es una función Java quedevuelve void.

p En general pueden ser invocadas de igual forma queun bloque PL/SQL (en Oracle).

p Ventajas:< Potencia expresiva de la que carece PL/SQL< Fuerte sistema de tipos< Portabilidad< Capacidad absoluta de interacción con el SGBD< Se ejecutan con los permisos del que invoca< Es ejecutado por una JVM independiente del SGBD

Capítulo 1: Introducción.

JDBC

p JDBC (Java Database Connectivity) es elmecanismo estándar de acceso a bases de datosrelacionales.

p JDBC permite al programador conectarse condistintas bases de datos y conocer “al vuelo” suscaracterísticas y deficiencias con respecto al SQLestándar.

p JDBC permite realizar consultas, actualizaciones,inserciones y borrados de registros.

p JDBC permite la ejecución de sentencias SQL pre-escritas (entrecomilladas), por lo que es propenso aerrores.

p Las sentencias pueden ser simples o con variablesde enlace (bind), lo que permite reutilizar una mismasentencia varias veces con distintos parámetros.

p A través de JDBC también es posible invocar aprocedimientos almacenados, así como a funciones.

p También es posible conectar la salida estándar deJava con la salida de SQL*Plus.

Capítulo 1: Introducción.

SQLJp SQLJ es un mecanismo para programar en JDBCsin utilizar cadenas entrecomilladas, por lo que noestan propenso a errores en ejecución.

p SQLJ no sólo permite ejecutar sentencias escritas enSQL nativo, sino que también permite gestionar losresultados de las consultas mediante unpseudolenguaje parecido al PL/SQL.

p SQLJ es un estándar aún no soportado por lamayoría de SGBDR.

p SQLJ consiste en escribir sentencias SQL dentro delpropio código Java. Posteriormente, mediante un pre-compilador estas sentencias se traducen a JDBC puro.

p Tanto JDBC como SQLJ permiten trabajar inclusocon tipos definidos por el propio usuario.

Capítulo 1: Introducción.

OC4Jp OC4J (Oracle Components For Java) es unatecnología que establece un acceso multicapa a la basede datos.

p Una capa de negocio permite acceder a las tablas através de objetos Java, así como validar la informaciónde las tablas.

p Una capa de presentación permite suministrar losdatos a las aplicaciones clientes. En esta capa sepueden definir datos calculados.

p Las capas clientes pueden acceder a los datos através de las vistas de presentación y trabajar con elloscomo se quiera.

p Los componentes OC4J se pueden depositar en lamáquina en la que se encuentra el cliente, perotambién se pueden depositar en contenedores J2EE,con lo que son accesibles remotamente.

p Esto permite gestionar los mismos OC4J conclientes de diversa índole: aplicaciones Java, JSP,formularios ADF, etc.

Capítulo 1: Introducción.

JDeveloperp Jdeveloper es el entorno de desarrollo de Oraclepara componentes OC4J, procedimientosalmacenados, SQLJ, aplicaciones clientes, páginasJSP, etc.

p Con Jdeveloper resulta mucho más sencillo eldesarrollo de aplicaciones, pero es un entorno querequiere un equipo potente.

p Posee una gran cantidad de asistentes que facilitanla creación de componentes de cualquiera de las capasmencionadas: negocios, presentación y clientes.

p También permite trabajar con contenedores J2EE,y Oracle9iAS. Para J2EE incorpora su propiocontenedor de pruebas, aunque en producción seaconseja usar Oracle9iAS.

p Permite realizar diferentes deposiciones de losmismos componentes, ya sean procedimientosalmacenados, OC4J local o en contenedor J2EE,aplicaciones, etc.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -1-

Capítulo 2: Procedimientos almacenados en Java.

Capítulo 2 Procedimientos almacenados

en Javap Los pasos para almacenar un procedimiento Java enOracle son:

1.- Codificar una clase Java con el métododeseado.2.- Cargar el método Java en el SGBD y resolverlas referencias externas.3.- Hacer público el método Java en el SGBD,mediante una especificación PL/SQL.4.- Asignar los permisos necesarios para invocar alprocedimiento.5.- Invocar al procedimiento, bien desde SQL odesde PL/SQL.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -2-

Capítulo 2: Procedimientos almacenados en Java.

Ejemplo. Paso 1: codificaciónp Como ejemplo, se creará una función que calcula lalongitud de una cadena SQL.

p Estática pues no se ejecuta en el contexto de unobjeto:

// (c) Bulusupublic class SLength{

public static int computeLength(String s){int retorno = s.length();return retorno;

}}

p Nótese que a PL/SQL no le es posible invocardirectamente a String.length(); de ahí la necesidadde esta clase Java.

p Si es posible, es conveniente probar la clase Javaantes de meterla en la base de datos.

public class Prueba{public static void main(String[] args){

if (args.length == 0)System.out.println("Pásame un texto comoparámetro");

else System.out.println(SLength.computeLength(args[0]));

}}

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -3-

Capítulo 2: Procedimientos almacenados en Java.

Ejemplo. Paso 2: cargap La utilidad loadjava permite meter en la base dedatos:

< Fuentes .java< Clases .class< Ficheros .jar y .zip< Ficheros de recursos Java .res< Ficheros SQLJ .sqlj

loadjava -user SCOTT/TIGER -oci8 -resolve SLength.class

-user: Carga los ficheros como el usuario indicado.-oci8: Se comunica con la base de datos a través del

driver OCI.-resolve: Resuelve las referencias externas

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -4-

Capítulo 2: Procedimientos almacenados en Java.

Ejemplo. Paso 3: publicaciónp La publicación construye una función oprocedimiento PL/SQL asociándolo con el códigoJava.

p PL/SQL hace homogéneo el acceso a los métodomediante una única sintaxis, da igual que el métodosubyacente sea Java o PL/SQL.

CREATE OR REPLACE FUNCTION F_SLENGTH(s IN VARCHAR2)RETURN NUMBERAS LANGUAGE JAVA NAME'SLength.computeLength(java.lang.String) return int';

p A la función Java se le da un alias que será aquélpor el que se la pueda invocar desde SQL o PL/SQL:F_SLENGTH.

p Nótese que el tipo de los parámetros (y resultado)de la especificación Java debe estar calificado porcompleto (incluye el package).

p La publicación la debe hacer quien hayaincorporado la clase Java a la base de datos.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -5-

Capítulo 2: Procedimientos almacenados en Java.

Ejemplo. Pasos 4 y 5: permisos einvocación

p En este caso, si nos conectamos comoSCOTT/TIGER no necesitaremos asignar permisosde acceso, ya que somos el propietario.

p Ahora es posible invocar la función F_SLENGTHde PL/SQL como si de cualquier otra se tratara:

select f_slength('hola') from dual;

o bienDECLARE

RET_VAL NUMBER;BEGIN

RET_VAL := F_SLENGTH('Ejemplo de prueba');dbms_output.put_line(to_char(ret_val));

END;

No olvidar el: set serveroutput on

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -6-

Capítulo 2: Procedimientos almacenados en Java.

loadjavap Algunos parámetros de loadjava son:

Parámetro Descripción-debug Genera y visualiza información de depuración

-force Carga las clases aunque ya hayan sidopreviamente cargadas

-grant Les da permiso de EXECUTE a los usuariosindicados

-help Visualiza la ayuda

-oci8 Se comunica con Oracle a través del driver OCI

-thin Se comunica con Oracle a través del driver thin100% Java

-resolve Resuelve las referencias externas

-resolver Permite indicar paquetes de otros esquemas conlos que se debe realizar la resolución dereferencias externas

-schema Carga los ficheros en el esquema indicado. Pordefecto es el de -user

-user Se conecta a la base de datos con el usuario yclave indicados

-verbose Visualiza información sobre la ejecución deloadjava

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -7-

Capítulo 2: Procedimientos almacenados en Java.

Consideraciones sobre loadjavap Esta utilidad carga los ficheros en una tabla temporal concolumnas BLOB y luego invoca a CREATE JAVA ...

p Una vez que todos los ficheros han sido cargados en la basede datos, loadjava lanza una sentencia ALTER JAVA CLASS ...RESOLVE para asegurarse de que las clases Java son completas,esto es, ninguna hace uso de una clase que no esté en el sistema.

p Es posible cargar un fichero fuente. En tal caso no se puedencargar sus .class. Además, para recargar el fuente primero hayque descargarlo con dropjava.

p Es conveniente compilar fuera del SGBD y cargar las clasesen la base de Datos.

p Es posible compilar dentro de Oracle: para ello se cargan sólolos fuentes que serán automáticamente compilados con la opción-resolve.

p Es posible dar opciones de compilación con el paqueteDBMS_JAVA.

p Si hay errores de compilación, se almacenarán enUSER_ERRORS.

p USER_OBJECTS guarda la información sobre loscomponentes Java cargados

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -8-

Capítulo 2: Procedimientos almacenados en Java.

Publicaciónp Establece una correspondencia entre la nomenclaturaPL/SQL y la nomenclatura Java.

p No supone una capa más en ejecución, por lo que esbastante eficiente.

p Sólo se pueden publicar los métodos public static. Noobstante los métodos públicos de instancia también se puedenpublicar, pero sólo como miembros de un objeto SQL.

p Se permite la sobrecarga.

p Se deben tener en cuenta tres cosas:< Correspondencia entre tipos Java y SQL.< Tipos de parámetros: entrada, salida y ent/sal.< Privilegios de ejecución.

p Si la función Java retorna void entonces se debe declararun PROCEDURE PL/SQL en vez de una FUNCTION.

p La declaración PL/SQL puede ser a nivel del sistema o anivel de un paquete. En este último caso, la asociación entrePL/SQL y Java se hace en el PACKAGE BODY.

p También es posible declarar un objeto SQL y añadirlemétodos en Java

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -9-

Capítulo 2: Procedimientos almacenados en Java.

Correspondencia entre tiposp Es la siguiente:

SQL JavaCHAR, NCHAR,LONG,VARCHAR2,NVARCHAR2

oracle.sql.CHARjava.lang.Stringjava.lang.Bytejava.lang.Shortjava.lang.Integerjava.lang.Longjava.lang.Floatjava.lang.Doublejava.math.BigDecimaljava.sql.Datejava.sql.Timebyte, short, int, long, float, double

DATE oracle.sql.DATEjava.sql.Datejava.sql.Timejava.sql.Timestamp

NUMBER oracle.sql.NUMBERjava.lang.Bytejava.lang.Shortjava.lang.Integerjava.lang.Long java.lang.Floatjava.lang.Doublejava.math.BigDecimalbyte, short, int, long, float, double

RAW, LONGRAW

oracle.SQL.RAWbyte[]

ROWID oracle.SQL.ROWIDjava.lang.String

Otros tipos Propios de Oracle

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -10-

Capítulo 2: Procedimientos almacenados en Java.

Tipos de parámetrosp Para poder pasar valores nulos no se pueden usar los tiposprimitivos de Java: int, etc.

p Los subtipos de SQL (INTEGER, REAL y FLOAT)carecen de correspondencia.

p El tipo boolean de Java no tiene correspondiente enPL/SQL.

p Por defecto los parámetros son todos de tipo IN, que secorresponde con el paso de parámetros por valor de Java.

p Para pasar parámetros de forma IN y OUT se emplea unarray de un solo elemento; p.ej. un parámetro number de INOUT se corresponde en Java con int io[];

p Cada parámetro de la función Java se debe correspondercon uno de PL/SQL. La única excepción es una función maincuyo parámetro String[] se puede corresponder con variosparámetros PL/SQL.

p Se recuerda que si la función Java no tiene parámetros, nisiquiera es necesario indicar la lista vacía en la declaraciónPL/SQL.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -11-

Capítulo 2: Procedimientos almacenados en Java.

Creación de Tipos en Oraclep En Oracle es posible crear tipos de datos nuevos conCREATE TYPE ... AS OBJECT, así como asignarle métodos,ya sean de clase (STATIC) o de instancia (MEMBER).

p En Oracle El objeto Oracle puede estar soportado realmentepor un objeto Java. Para ello, la clase de Java debeimplementar la interface SQLData, que es estándar (paquetejava.sql.*), y posee las funciones:

< getSQLTypeName, que debe devolver el nombre conque se construyó el objeto Java con readSQL.

< readSQL, que permite construir el objeto Java a partirde uno en Oracle, al que se conecta un canal deentrada

< writeSQL, que permite cargar un objeto Oraclemediante un canal de salida.

que permiten que el programador establezca unacorrespondencia entre los componentes del objeto Java y delobjeto Oracle.

p Las funciones de la interfaz SQLData son invocadasautomáticamente por JDBC durante su relación con el SGBDde Oracle.

p Hay que tener cuidado con el paso de parámetros NULL aobjetos, ya que ello exige que se haga por referencia.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -12-

Capítulo 2: Procedimientos almacenados en Java.

Creación de Tipos en Oraclep El siguiente código se asociará más adelante a un tipo deOracle.

import java.sql.*;public class DireccionJefe implements SQLData{

private int id;private String descripcion;

public void crearDireccion(int id, String descripcion){this.id = id;this.descripcion = descripcion;

}

public void cambiarDireccion(String descripcion){this.descripcion = descripcion;

}

//Implementación de la interface.String SQLType;public String getSQLTypeName()

throws SQLException{return SQLType;

}public void readSQL(SQLInput canal, String typeName)

throws SQLException{SQLType = typeName;id = canal.readInt();descripcion = new String(canal.readString());

}public void writeSQL(SQLOutput canal)

throws SQLException{canal.writeInt(id);canal.writeString(descripcion);

}}

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -13-

Capítulo 2: Procedimientos almacenados en Java.

Creación de Tipos en Oraclep Y ahora en Oracle se puede escribir algo como:

- Crea el tipo DIRECCION_JEFE:CREATE OR REPLACE TYPE DIRECCION_JEFE AS OBJECT(

ID NUMBER(10),DESCRIPCION VARCHAR2(45),MEMBER PROCEDURE CREAR_DIRECCION(ID NUMBER, DESCRIPCION

VARCHAR2)IS LANGUAGE JAVA NAME

'DireccionJefe.crearDireccion(int,java.lang.String)',

MEMBER PROCEDURE CAMBIAR_DIRECCION(DESCRIPCION VARCHAR2)IS LANGUAGE JAVA NAME

'DireccionJefe.cambiarDireccion(java.lang.String)');

- Crea una tabla con un campo de tipo DIRECCION_JEFE:CREATE TABLE DIRECCIONES OF DIRECCION_JEFE;

- Mete un registro en la tabla anterior:DECLARE

DIR DIRECCION_JEFE := DIRECCION_JEFE(null, 'hola');texto varchar2(50);

BEGINDIR.CREAR_DIRECCION(1, 'DIRE DEL JEFE');INSERT INTO DIRECCIONES VALUES (DIR);

END;

- Visualiza el contenido de la tabla anterior:SELECT * FROM DIRECCIONES;

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -14-

Capítulo 2: Procedimientos almacenados en Java.

Otras invocacionesp También se puede invocar una función Java desde DML,con las siguientes restricciones:

- El método no puede tener parámetros OUT o IN-OUT.- No puede modificar ninguna tabla.- Tampoco puede consultar la tabla consultada omodificada.- No puede ejecutar sentencias DDL, ni de transacción, nide sesión ni ALTER SYSTEM.

p También se puede invocar desde un trigger, con las mismasrestricciones que cualquier procedimiento escrito en PL/SQL.

p También se puede invocar desde un bloque PL/SQL decualquier nivel, incluido el superior. Ej.:

VARIABLE lon NUMBER;CALL F_FLENGTH(‘Pablito clavó un clavito’) INTO :lon;PRINT lon;

p Más adelante estudiaremos cómo conectarnos a la base dedatos actual:Connection con =

OracleDriver().defaultConnection();

p Más adelante veremos como efectuar llamadas a PL/SQLdesde el interior de funciones Java.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -1-

Capítulo 3: Java Database Connectivity.

Capítulo 3 Java Database Connectivity

p JDBC proporciona proporciona una interfazestándar de acceso a bases de datos relacionales.

p JDBC es independiente de dónde se encuentre elcliente y dónde esté el servidor. p JDBC consiste en una API de alto nivel y diferentesdrivers cada uno para conectarse a una base de datosdistinta. p Estos drivers pueden ser de cuatro tiposfundamentalmente:Tipo 1 (JDBC/ODBC): Necesita que la base de datos esté dada de altaen ODBC. Supone un puente de comunicaciones entre JDBC y ODBC.

< Tipo 2 (API Nativa): Es un tipo de driver totalmente propietario yque explota al máximo las características de una base de datosconcreta.

< Tipo 3 (Protocolo de red abierto): A diferencia de las anteriores,permite accesos por red. Estos accesos usan protocolosindependientes de los que proporcione la base de datos concreta ala que se conecta.

< Tipo 4 (Protocolo de red propietario): Igual que el anterior, perousando protocolos propios del SGBD.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -2-

Capítulo 3: Java Database Connectivity.

Cómo acceder a unabase de datos

p Un programa Java se conecta a una base de datoscon JDBC realizando las siguientes operaciones:

1. Importación de paquetes2. Carga del driver JDBC3. Conexión con la base de datos4. (Opcional) Averiguar las capacidades de la

base de datos5. (Opcional) Obtención de metadatos propios del

esquema al que nos hemos conectado6. Construcción de la sentencia SQL y ejecución7. Procesamiento de resultados, si los hay8. Cierre de la sentencia y del cursor, si lo hay9. Cierre de la conexión

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -3-

Capítulo 3: Java Database Connectivity.

Drivers JDBC de Oraclep Oracle proporciona los siguientes drivers deconexión:

Thin cliente: driver 100% Java, tipo 4. Da la máximaportabilidad, ya que simula TTC sobre TCP/IP.

OCI (Oracle Call Interface) cliente: driver nativo,tipo 2. Convierte las llamadas JDBC en llamadas OCI.

Thin servidor: igual que el Thin cliente pero internoa un servidor. Permite el acceso a bases de datosremotas. Este es el driver que se utiliza dentro de losprocedimientos almacenados.

Interno al servidor: igual que el anterior pero sóloaccede a la base de datos actual.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -4-

Capítulo 3: Java Database Connectivity.

Ejemplo preliminarp Ejemplo con driver Thin y sentencia SELECT:

import java.sql.*;public class EjemploConsulta{

public static void main(String args[]){try{

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:oracle", "scott", "tiger");

Statement stmt = conn.createStatement();ResultSet rset = stmt.executeQuery(

"SELECT empno, ename, sal "+"FROM emp order by ename");

while (rset.next()){System.out.println(

rset.getInt(1) + "-" +rset.getString("ename") + "-" +rset.getFloat("sal")

);}rset.close();stmt.close();conn.close();

}catch(SQLException x){x.printStackTrace();

}}

}

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -5-

Capítulo 3: Java Database Connectivity.

JDBC 2.0p JDBC 1.0 permite accesos más o menos básicos auna base de datos. p JDBC 2.0 permite muchas más cosas:< Los cursores (llamados resultset), se pueden

recorrer de arriba abajo o viceversa, inclusocambiando el sentido.

< Se admite un mayor número de tipos de datos.< Pool de conexiones. Para no estar conectándose y

desconectándose continuamente (lo que consumerecursos), los drivers OCI y Thin proporcionan unpool de conexiones permanentemente abiertas.

< Transacciones distribuidas. Paquetes javax.sql.* enel lado cliente. En el caso de Oracle, usar elpaquete oracle.jdbc.xa.client.*.

p El JDK 1.2 es compatible con JDBC 2.0 a través delpaquete java.sql.*. Desde Oracle, lo que se usan sonlos paquetes oracle.sql.* y oracle.jdbc.driver.*, que seencuentran en classes12.jar del directorioE:\oracle\ora92\jdbc\lib, que hay que incluir en elCLASSPATH.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -6-

Capítulo 3: Java Database Connectivity.

Importación de paquetes yCarga del driver

p El paquete fundamental que debe cargarse esjava.sql.*

p Si va a hacerse uso de las características avamzadasde Oracle, habrá que importar tambiénoracle.jdbc.driver.* y oracle.sql.*

p La carga del driver se hace una sola vez en toda laaplicación. El mismo driver permite múltiplesconexiones, incluso simultáneas.

p El driver es una clase java. En nuestro caso:oracle.jdbc.driver.OracleDriver

p El driver puede cargarse de dos formas:DriverManager.registerDriver(

new oracle.jdbc.driver.OracleDriver);ó

Class.forName(“oracle.jdbc.driver.OracleDriver”);pero se recomienda el 1er método por ser más explícitoy no propenso a errores en ejecución.

p Como puede verse, todos los drivers songestionados por la clase DriverManager.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -7-

Capítulo 3: Java Database Connectivity.

Conexión a la base de datosp Una conexión a la base de datos produce un objetode tipo Connection.

p Las conexiones se le piden al gestor de drivers(DriverManager)., mediante el mensajegetConnection().

p getConnection toma tres parámetros de tipo String:cadena de conexión, usuario y contraseña.

p La cadena de conexión tiene un formato muyconcreto y propenso a errores ortográficos:

jdbc:oracle:oci8:@sidjdbc:oracle:thin:@host:puerto:sid

p Con el driver Thin no se usa la entradaTNSNAMES, por lo que hay que indicar el host y elpuerto directamente.

p El host y el puerto también pueden especificarse, sise desea, con el driver oci8.

p En un procedimiento almacenado, la conexión conla base de datos actual se consigue mediante:

Connection conn = new OracleDriver().defaultConnection();

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -8-

Capítulo 3: Java Database Connectivity.

Consulta a la base de datosp Toda sentencia está asociada a una conexión.

p Por ello, las sentencias se le solicitan a lasconexiones con:

conn.getStatement()ó

conn.prepareStatement(TextoSQL)que devuelven un objeto de tipo Statement.

p Una sentencia no preparada se ejecuta con:stmt.executeQuery(TextoSQL)

óstmt.executeUpdate(TextoSQL)

según se trate de una consulta o de un INSERT,UPDATE o DELETE.

p Un executeQuery devuelve un cursor,implementado con un objeto de tipo ResultSet.

p Las sentencias preparadas permiten utilizar valoresde enlace (bind). Las veremos más adelante.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -9-

Capítulo 3: Java Database Connectivity.

Procesamiento del ResultSetp El procesamiento se divide en dos partes:Acceso a los registros obtenidos, de uno en uno.Obtención de los valores de las columnas, de una enuna.

p El acceso a los registros se hace en base al métodonext() de los ResultSet., que devuelve un valorbooleano que indica sy hay o no siguiente registro.

p Las columnas pueden ser accedidas por nombre(String), o por posición (en caso de que haya camposcalculados).

p Para ello se usa un método que depende del tipo dela columna obtenida: getInt, getString, getFloat, etc.

p Cada una de estas funciones toma como parámetroel nombre de la columna o bien la posición que ocupa.

while (rset.next()){System.out.println(

rset.getInt(1) + "-" +rset.getString("ename") + "-" +rset.getFloat("sal")

);}

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -10-

Capítulo 3: Java Database Connectivity.

Cierresp Una vez procesador un ResultSet hay que cerrarlo,así como la sentencia que lo originó.

p Caso de no hacerlo se estarán ocupando cursores ybloques de memoria innecesarios, pudiendo producirseun error al superar el número máximo de cursoresabiertos.

p Una vez que se haya acabado todo el procesamientocon la base de datos, se debe cerrar la conexión.

p La conexión se abre una sola vez al comienzo de lasesión y se cierra una vez acaba la sesión. Una mismasesión puede ejecutar múltiples sentencias.

p Tanto los ResultSet, las Statement y lasConnection se cierran con close().

p Por último, indicar que los métodos relacionadoscon SQL pueden lanzar la excepción SQLException,por lo que todo ha de enmarcarse en un try-catch.

p A efectos de depuración es conveniente indicare.printStackTrace() en la parte catch.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -11-

Capítulo 3: Java Database Connectivity.

Sentencias preparadasp Una sentencia preparada es una sentenciaprocedente de un texto SQL con “huecos”.

p Una sentencia preparada se obtiene mediante:PreparedStatement stmt = conn.prepareStatement(TextoSQL);donde el TextoSQL coloca un ? En cada lugar donde seespera un literal. Ej:”INSERT INTO emp VALUES (?, ?, ?, ?, ?, ?, ?, ?)”

p Cada hueco está a la espera de recibir un valorliteral.

p Los huecos se referencian por posición. En funcióndel tipo de datos que cada hueco vaya a albergar, seutiliza una determinada función para cargar su valor.:setInt, setString, setFloat, etc. Ej.:

stmt.setInt(posición, valor)

p Una vez cargados todos los “huecos” de unasentencia preparada, ésta se ejecuta medianteexecuteQuery() , si es un SELECT, oexecuteUpdate() si es un INSERT, UPDATE oDELETE.

p Nótese que executeQuery y executeUpdate notienen parámetros en las sentencias preparadas.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -12-

Capítulo 3: Java Database Connectivity.

Ejemplo de sentencia preparadap A continuación se muestra el ejemplo anterior consentencia preparada.import java.sql.*;public class EjemploConsultaPreparada{

public static void main(String args[]){try{

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:oracle", "scott", "tiger");

PreparedStatement stmt = conn.prepareStatement("SELECT empno, ename, sal FROM emp " +"WHERE sal >= ? ORDER BY ename");

double prueba[] = {1300.00, 2000.00, 3000.00};for(int i=0; i<prueba.length; i++){

stmt.setDouble(1, prueba[i]);ResultSet rset = stmt.executeQuery();System.out.println("Probando con "+prueba[i]);while (rset.next()){

System.out.println(rset.getInt(1) + "-" +rset.getString("ename") + "-" +rset.getFloat("sal")

);}rset.close();

}stmt.close();conn.close();

}catch(SQLException x){x.printStackTrace();

}}

}

p Nótese como una sentencia se puede reutilizar, perocerrando los cursores que ya no hagan falta.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -13-

Capítulo 3: Java Database Connectivity.

Acceso a la base de datosen procedimientos almacenados

p Hasta ahora hemos visto procedimientos almacenados que noacceden a la base de datos, lo cual no es de mucha utilidad.p Un procedimiento almacenado accede a la base de datos actualcogiendo la conexión con

Connection conn = new OracleDriver().defaultConnection();y sin que sea necesario registrar el driver. Tampoco es necesariocerrar la conexión. También se puede hacer:Connection conn=

DriverManager.getConnection(“jdbc:default:connection”);

import java.sql.*;import oracle.jdbc.driver.*;public class ConsultaProcedimientoAlmacenado{

public static int countConsulta(double sal) throws SQLException {

int retorno;Connection conn =

new OracleDriver().defaultConnection();PreparedStatement stmt =

conn.prepareStatement("SELECT empno, ename, sal "+"FROM emp WHERE sal >= ? ORDER BY ename");

stmt.setDouble(1, sal);ResultSet rset = stmt.executeQuery();retorno = 0;while (rset.next())

retorno ++;rset.close();stmt.close();return retorno;

}}c:\>loadjava -user scott/tiger@oracle -oci8 -resolve ConsultaProcedimientoAlmacenado.classSQL>CREATE OR REPLACE FUNCTION CONSULTA_SUELDO(SAL NUMBER) RETURN NUMBERIS LANGUAGE JAVANAME 'ConsultaProcedimientoAlmacenado.countConsulta(double) return int';

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -14-

Capítulo 3: Java Database Connectivity.

Acceso a proc. almacenadosp Las llamadas a procedimientos almacenados songestionadas por un tipo especial de sentencia:CallableStatement.

p Se obtienen enviando a la conexión el mensajeprepareCall(“{call nombre_proc(?, ?, ?)}”)

p Los parámetros de entrada se gestionan igual que enuna PreparedStatement.

p Los parámetros de salida deben registarse antes dela llamada, con: registerOutParameter(pos, tipo).

p Los tipos de los parámetros se toman de la clasejava.sql.Types

p La invocación se hace con executeUpdate().

p Una vez ejecutada la llamada, los parámetros desalida se obtienen con getTipo(pos), tal y como si setratara de un ResultSet (pero sin next()).

p Caso de llamar a una función, se hace:prepareCall(“{ ? = call nombre_proc(?, ?, ?)}”)donde el 1er ? se trata como un parámetro de salida.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -15-

Capítulo 3: Java Database Connectivity.

Ejemplo de llamada aDBMS_OUTPUT

p El siguiente ejemplo ilustra cómo visualizar datospor pantalla.import java.sql.*;import oracle.jdbc.driver.*;public class ConsultaProcedimientoAlmacenado{

public static void consulta(double sal) throws SQLException {

int retorno;Connection conn =

new OracleDriver().defaultConnection();PreparedStatement stmt =

conn.prepareStatement("SELECT empno, ename, sal "+"FROM emp WHERE sal >= ? ORDER BY ename");

stmt.setDouble(1, sal);ResultSet rset = stmt.executeQuery();CallableStatement cStmt = conn.prepareCall(

"{call DBMS_OUTPUT.PUT_LINE("+"to_char(?)||' '||?||' '||to_char(?))}");

while (rset.next()){cStmt.setInt(1, rset.getInt(1));cStmt.setString(2, rset.getString(2));cStmt.setDouble(3, rset.getDouble(3));cStmt.executeUpdate();

}cStmt.close();rset.close();stmt.close();

}}

p Se puede conseguir que los System.out.println deJava se vean en la consola SQL, ejecutando en dichaconsola: CALL dbms_java.set_output(2000);

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -16-

Capítulo 3: Java Database Connectivity.

Procesamiento básico detransacciones

p Por defecto, JDBC hace un COMMIT automáticotras cada INSERT, UPDATE, o DELETE (excepto sise trata de un procedimiento almacenado).

p Este comportamiento se puede cambiar mediante elmétodo setAutoCommit(boolean) de la claseConnection.

p Para hacer un COMMIT, la clase Connection poseeel método commit().

p Para hacer un ROLLBACK, la clase Connectionposee el método rollback().

p Si se cierra la conexión sin hacer commit() orollback() explícitamente, se hace un COMMITautomático, aunque el AUTO COMMIT esté a false.

p También se permite el establecimiento/recuperaciónde/a puntos de salvaguarda con (propio de JDBC 3.0):Savepoint setSavepoint(String nombre)yrollback(Savepoint sv)

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -17-

Capítulo 3: Java Database Connectivity.

Gestión de ResultSetp En JDBC 1.0 los ResultSet sólo se pueden recorrerde arriba abajo. Además, son de sólo lectura.

p JDBC 2.0 permite que los ResultSet se puedanrecorrer en ambos sentidos, permite posicionarse en unregistro concreto e introduce posibilidades deactualización (concurrencia).

p Un ResultSet puede ser de tres tipos:ResultSet.TYPE_FORWARD_ONLY. Sólo sepuede recorrer de arriba abajo. Es el tipo por defecto.ResultSet.TYPE_SCROLL_INSENSITIVE. Se puederecorrer en cualquier sentido. Pero es insensible a loscambios efectuados por la misma transacción, o porotras transacciones finalizadas con éxito (COMMIT).ResultSet.TYPE_SCROLL_SENSITIVE. Igual queel anterior, pero sensible a cambios.

p Para obtener un ResultSet de alguno de estos tiposse especifica su tipo en los métodos:createStatement(int resultSetType, int resultSetConcurrency);prepareStatement(String sql, int resultSetType, intresultSetConcurrency);prepareCal l (Str ing sql , in t resul tSetType, in tresultSetConcurrency);

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -18-

Capítulo 3: Java Database Connectivity.

ResultSet con scrollp En un ResultSet con scroll se pueden usar lossiguientes métodos (si el ResultSet esTYPE_FORWARD_ONLY se producirá unaexcepción SQL):

boolean first() //Se pone al comienzo del ResultSet. Si éste estávacío retorna false, si no true.

boolean last() // Igual que el anterior, pero al final.boolean previous() // Pasa al registro anterior al actual. Si no hay

registro anterior devuelve false, si no true.boolean next() // Igual que el anterior, pero al posterior.boolean absolute(int rowNum) // Se va al registro indicado. Si se

pasa, se queda en beforeFirst o afterLast. Devuelve truesi el número de registro es válido.

boolean relative(int offset) // Igual que el anterior pero de formarelativa.int getRow() // Devuelve el número de registro actualvoid beforeFirst() // Se posiciona antes del primer registro.boolean isBeforeFirst() // true si se está antes del primer registro.void afterLast() // Se posiciona tras el último registro.boolean isAfterLast() // true si se está tras el último registro.boolean isFirst() // true si se está en el primer registro.boolean isLast() // true si se está en el último registro.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -19-

Capítulo 3: Java Database Connectivity.

Ejemplo de ResultSet con scrollp Nótese cómo el siguiente ejemplo funciona inclusocambiando el 1300 por un 7300, de manera que elResultSet generado no posea ningún registro.

import java.sql.*;pimport java.sql.*;public class ResultSetScrollable{

public static void main(String args[]){try{

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:oracle", "scott", "tiger");

Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

ResultSet rset = stmt.executeQuery("SELECT empno, ename, sal FROM emp "+"WHERE sal >= 1300");

rset.last();System.out.println(rset.getRow());rset.close();stmt.close();conn.close();

}catch(SQLException x){x.printStackTrace();

}}

}

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -20-

Capítulo 3: Java Database Connectivity.

ResultSet actualizablep Para indicar si un ResultSet se puede actualizar o no, seusan las constantes:ResultSet.CONCUR_READ_ONLY. No permiteacciones DML.ResultSet.CONCUR_UPDATABLE. Permite accionesDML, tanto UPDATE como INSERT y DELETE.

p Para hacer estas operaciones, la consulta debe serconsiderada UPDATABLE por Oracle.

p UPDATE. Una vez posicionado en el registro amodificar, ejecutar updateTipo(pos, nuevoValor), dondepos representa la columna por posición (esto implica queespecificar * en el SELECT no funcionará). Una vezactualizados todos los campos oportunos, ejecutarupdateRow(). Las actualizaciones realizadas puedencancelarse (si el AUTO COMMIT está a false), concancelRowUpdates().

p INSERT. Ejecutar moveToInsertRow(), que seposiciona en un registro “fantasma”. A continuación,actualizar los campos como si fuera un UPDATE, y porúltimo ejecutar un insertRow().

p DELETE. Una vez posicionados en el registro a borrar,ejecutar deleteRow().

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -21-

Capítulo 3: Java Database Connectivity.

Ejemplo de ResultSetactualizable

p Vamos a subirle el sueldo a todo el mundo en un 5% más100i.

import java.sql.*;public class SubidaSueldo{

public static void main(String args[]){try{

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:oracle", "scott", "tiger");

Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

ResultSet rset = stmt.executeQuery("SELECT empno, ename, sal FROM emp");

while(rset.next()){rset.updateDouble("sal", rset.getDouble("sal")*1.5+100.0);rset.updateRow();

}rset.close();stmt.close();conn.close();

}catch(SQLException x){x.printStackTrace();

}}

}

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -22-

Capítulo 3: Java Database Connectivity.

Metadatos de ResultSetp Cuando un ResultSet recoge datos de una consultadesconocida (p.ej., introducida por teclado), no se sabequé campos obtener.

p Para saber la estructura de una consulta se utiliza laclase ResultSetMetaData.

p Sus funciones más interesantes son:int getColumnCount(); // Número de campos por registro.String getColumnName(int i) // Nombre de la columna i-ésima.Int getColumnType(int i) // Tipo de la columna i-ésima.

p Los tipos de las columnas vienen definidos por lasconstantes de java.sql.Types.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -23-

Capítulo 3: Java Database Connectivity.

Ejemplo de Metadatos de ResultSet

p Probar el siguiente ejemplo.

import java.sql.*;public class SelectDesconocido{

public static void main(String args[]){if (args.length == 0)

System.out.println("Necesito un argumento.");else try{

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:oracle", "scott", "tiger");

Statement stmt = conn.createStatement();ResultSet rset = stmt.executeQuery(args[0]);ResultSetMetaData rsetMD = rset.getMetaData();for(int i=1; i<=rsetMD.getColumnCount(); i++)

System.out.print(rsetMD.getColumnName(i)+" ");System.out.println("");while(rset.next()){

for(int i=1; i<=rsetMD.getColumnCount(); i++)if (rsetMD.getColumnType(i) == Types.VARCHAR)

System.out.print(rset.getString(i)+" ");else

System.out.print(""+rset.getDouble(i)+" ");System.out.println("");

}rset.close();stmt.close();conn.close();

}catch(SQLException x){x.printStackTrace();

}}

}

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -24-

Capítulo 3: Java Database Connectivity.

Metadatos de la base de datosp Los metadatos accesibles por la sesión actualpueden obtenerse a través de la conexión.

p Para ello se emplea el método getMetaData() quedevuelve un objeto de tip DatabaseMetaData.

p Este es uno de los objetos más complejos de todoJava.

p Por supuesto, es posible acceder a las tablas demetadatos de Oracle sin hacer uso de este objeto(como una consulta cualquiera), pero con ello seperdería portabilidad.

p El siguiente ejemplo muestra las tablas de las que espropietario el usuario actual.

DatabaseMetaData dbaseMD = conn.getMetaData();ResultSet rset = dbaseMD.getTables(null, "SCOTT", null, null);while(rset.next()){

System.out.print(rset.getString("TABLE_CAT")+" ");System.out.print(rset.getString("TABLE_SCHEM")+" ");System.out.print(rset.getString("TABLE_NAME")+" ");System.out.println(rset.getString("TABLE_TYPE")+" ");

}

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -25-

Capítulo 3: Java Database Connectivity.

Gestión de Large Objectsp Los “objetos grandes” que permite JDBC son los BLOBS yCLOBS. Los BFILE se gestionan mediante una extensión deOracle.

p Ejemplo de creación de tabla e inserción de datos:CREATE TABLE lob_table(

id NUMBER PRIMARY KEY,blob_data BLOB,clob_data CLOB

);INSERT INTO lob_table VALUES (1, empty_blob(), empty_clob());

p Realmente, lo que se almacena en la tabla no son los bytes quecontienen los objetos grandes sino un localizador a los mismos.

p Un objeto grande se gestiona obteniendo, a partir de sulocalizador, canales de entrada o salida para leerlo o escribirlo.Por tanto, se puede actualizar un objeto grande a través de unsimple SELECT...FOR UPDATE. Evidentemente, lasactualizaciones de un objeto grande no están sujetas a COMMITy ROLLBACK.

p Los localizadores no se pueden crear en JDBC, sólo en SQL.

p Oracle no soporta java.sql.Blob, por lo que hay que usaroracle.sql.BLOB

p Con java.sql.Blob se puede trabajar directamente con losbytes del BLOB, sin necesidad de canales de E/S.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -26-

Capítulo 3: Java Database Connectivity.

Ejemplo de escritura de BLOBp El siguiente ejemplo mete el fichero que se indique como BLOB enla tabla anterior.import java.sql.*;import java.io.*;import oracle.jdbc.driver.*;import oracle.sql.*;public class MeteBLOB{

public static void main(String args[]){if (args.length != 2) System.out.println("Necesito 2 argumentos.");else try{

DriverManager.registerDriver(new OracleDriver());Connection conn = DriverManager.getConnection(

"jdbc:oracle:thin:@localhost:1521:oracle", "scott", "tiger");

conn.setAutoCommit(false);Statement stmt = conn.createStatement();stmt.executeUpdate(

"INSERT INTO lob_table VALUES ("+args[0]+", empty_blob(), empty_clob())");

ResultSet rset = stmt.executeQuery("SELECT blob_data FROM lob_table where id = "+args[0]+" FOR UPDATE");

if (rset.next()) try {BLOB blob_data = ((OracleResultSet)rset).getBLOB(1);int tamañoBuffer = blob_data.getBufferSize();;OutputStream out = blob_data.getBinaryOutputStream();BufferedInputStream in = new BufferedInputStream(

new FileInputStream(args[1]),tamañoBuffer

);byte[] chunk = new byte[tamañoBuffer];while (true){

int numBytes = in.read(chunk, 0, tamañoBuffer);if (numBytes == -1) break;out.write(chunk, 0, numBytes);

}in.close();out.close();

}catch(IOException x){ x.printStackTrace(); }rset.close();stmt.close();conn.close();

}catch(SQLException x){x.printStackTrace();

}}

}

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -27-

Capítulo 3: Java Database Connectivity.

Ejemplo de lectura de BLOBp El siguiente ejemplo lee un BLOB y lo guarda en elfichero que se indique.import java.sql.*;import java.io.*;import oracle.jdbc.driver.*;import oracle.sql.*;public class SacaBLOB{

public static void main(String args[]){if (args.length != 2)

System.out.println("Necesito 2 argumentos.");else try{

DriverManager.registerDriver(new OracleDriver());Connection conn = DriverManager.getConnection(

"jdbc:oracle:thin:@localhost:1521:oracle", "scott", "tiger");

conn.setAutoCommit(false);Statement stmt = conn.createStatement();ResultSet rset = stmt.executeQuery(

"SELECT blob_data FROM lob_table where id = "+args[0]);if (rset.next()) try {

BLOB blob_data = ((OracleResultSet)rset).getBLOB(1);int tamañoBuffer = blob_data.getBufferSize();;InputStream in = blob_data.getBinaryStream();BufferedOutputStream out = new BufferedOutputStream(

new FileOutputStream(args[1]),tamañoBuffer

);byte[] chunk = new byte[tamañoBuffer];while (true){

int numBytes = in.read(chunk, 0, tamañoBuffer);if (numBytes == -1) break;out.write(chunk, 0, numBytes);

}in.close();out.close();

}catch(IOException x){x.printStackTrace();

}rset.close();stmt.close();conn.close();

}catch(SQLException x){x.printStackTrace();

}}

}

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -28-

Capítulo 3: Java Database Connectivity.

Procesamiento batchp Es posible dejar pendientes una secuencia de sentencias yejecutarlas todas de golpe como si fuera un script completo.

p Esto sólo tiene sentido con operaciones idénticas que sólovarían en los valores de enlace. Deben ser de DML, y noSELECT. También se pueden invocar procedimientosalmacenados que no tengan parámetros de salida.

p Se supone que cada sentencia del proceso batch devuelve elnúmero de registros que ha actualizado.

p Para esto, en lugar de hacer executeQuery(), se haceaddBatch().

p Para ejecutar el proceso batch, se le envía a la sentencia unexecuteBatch().

p Ejemplo:conn.setAutoCommit(false);PreparedStatement stmt = conn.prepareStatement(

"INSERT INTO temp VALUES (?)");stmt.setInt(1, 123);stmt.addBatch();stmt.setInt(1, 746);stmt.addBatch();stmt.setInt(1, 837);stmt.addBatch();stmt.setInt(1, 998);stmt.addBatch();stmt.setInt(1, 388);stmt.addBatch();int[] numRegs = stmt.executeBatch();for(int i=0; i<numRegs.length; i++)

System.out.println(numRegs[i]);stmt.close();

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -1-

Capítulo 4: SQLJ.

Capítulo 4SQLJ

p SQLJ supone una interesante forma estándar deacceder a una base de datos.

p La ventaja sobre JDBC es que las sentencias SQLno se escriben como literales entrecomillados, sino quese precompilan, con lo que se evitan numerososerrores de ejecución.

p Al ser precompilado es más rápido.

p La desventaja es que las sentencias SQL que seejecutan deben ser estáticas (aunque pueden tenervariables de enlace -bind-). No obstante, es posiblesimular un comportamiento dinámico.

p El proceso de trabajo con la base de datos es muyparecido al de JDBC: carga del driver y conexión,captura de excepciones y cierre de la conexión. Tansólo varía un poco la recuperación de datos y laasignación de valores en sentencias preparadas.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -2-

Capítulo 4: SQLJ.

Ejecución de un fichero SQLJp Un fichero con extensión .sqlj es un fichero Javaque tiene inmersas directivas SQLJ. El proceso paraconvertir un .sqlj en un .class es el siguiente:

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -3-

Capítulo 4: SQLJ.

Declaraciones SQLJp SQLJ permite dos tipos de declaraciones:declaraciones puras y de variables Java.

p Las declaraciones puras permiten declarar unIterator (para recorrer el resultado de un SELECT) obien la Connection por defecto con la que se van ahacer las operaciones (por si hay más de una conexiónsimultánea). Ejs.:

#sql public iterator EmpIter (int empno, int enmae, int sal);ó

#sql public context miConnCtxt

p Tras la directiva #sql se coloca la sentencia SQL aejecutar entre { y }. Esta sentencia puede contenerexpresiones Java precedidas por dos puntos :. Ej.:int hDeptno;#sql {UPDATE emp SET sal=sal*1.5 WHERE deptno = :hDeptno};ófloat hNuevoSal;#sql {UPDATE emp SET sal=:(1.5*hNuevoSal()) WHERE deptno =5};

p También es posible ejecutar una función PL/SQL yguardar el resultado ejecutando:int hSal;#sql hSal = {VALUES (funcionPL_SQL(parámetros))};

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -4-

Capítulo 4: SQLJ.

Establecimiento de la conexiónp Para realizar una conexión, es posible crear unfichero connect.properties que contiene lainformación de conexión. El contenido de este ficheropuede ser:# Ejemplo de fichero connect.propertiessqlj.url=jdbc.oracle.thin:@localhost:1521:oraclesqlj.user=scottsqlj.password=tiger

p Y la conexión se haría con:Oracle.connect(getClass(), “connect.properties”);Nótese que no es necesario registrar el driver.

p Para ello hay que importar la claseoracle.sqlj.runtime.Oracle p La conexión también puede hacerse de la forma: Oracle.connect(“jdbc.oracle.thin@localhost:1521:oracle”, “scott”, “tiger”); p Sea cual sea la forma en que se ha obtenido laconexión, ésta es la que se utilizará por defecto encualquier sentencia SQLJ.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -5-

Capítulo 4: SQLJ.

Establecimiento de la conexiónp Si nuestro programa realiza varias conexionessimultáneas, entonces hay que indicarle a lassentencias SQLJ cuál queremos utilizar.

p Lo primero que hay que hacer es almacenar lasdistintas conexiones en forma de objetosDefaultContext . Para ello util izaremosgetConnection() en lugar de connect() paraconectarnos a la base de datos, ya que getConnect()devuelve un objeto de tipo DefaultContext queusaremos posteriormente para ejecutar la sentenciaSQLJ.

p Desde Java se puede indicar la conexión por defectoejecutando:DefaultContext.setDefaultContext(contexto);

p En la propia directiva #sql se puede indicar elcontexto de ejecución:#sql contexto {sentencia SQL};

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -6-

Capítulo 4: SQLJ.

Primer programap A continuación se muestra un sencillo programaque inserta un registro en la tabla EMP (no olvidar elCOMMIT del final).

import java.sql.*;import oracle.sqlj.runtime.*;public class Primer{

public static void main(String[] args)throws SQLException {if (args.length != 2)

System.out.println("Necesito 2 argumentos.");else {

Oracle.connect(Primer.class, "connect.properties");#sql {INSERT INTO EMP(EMPNO, ENAME)

VALUES (:(args[0]), :(args[1]))};#sql {COMMIT};Oracle.close();

}}

}

p Este ejemplo hace uso del ficheroconnect.properties visto anteriormente.

p Nótese cómo se cierra la conexión por defecto. Encaso de disponer de un DefaultContext, deben cerrarsecada uno de ellos, con close().

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -7-

Capítulo 4: SQLJ.

SELECT con resultado simplep Cuando una sentencia SELECT retorna una únicatupla, los valores de ésta se pueden colocar envariables Java mediante la cláusula INTO. Si elSELECT no retorna nada o más de una fila, se produceun error.

import java.sql.*;import oracle.sqlj.runtime.*;public class SelectSimple{

public static void main(String[] args)throws SQLException {if (args.length != 1)

System.out.println("Necesito 2 argumentos.");else {

Oracle.connect(SelectSimple.class, "connect.properties");String ename;double sal;#sql {SELECT ename, sal INTO :ename, :sal

FROM emp WHERE empno = :(args[0])};System.out.println("Nombre: "+ename+". Salario: "+sal);Oracle.close();

}}

}

p Nótese cómo este ejemplo funciona aunque args[0]es de tipo String y empno es un NUMBER.

p Nótese cómo no es necesario que la variable enamehaya sido inicializada.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -8-

Capítulo 4: SQLJ.

SELECT con resultado múltiplep Cuando el SELECT devuelve cero o más de unafila, debe asignarse a un iterador.

p Existe una correspondencia unívoca entre cada tipode iterador y cada tipo de tupla retornada por unSELECT. Un ejemplo de declaración de iterador sería:#sql iterator EmpIter (int empno, String ename, double sal);que será capaz de recorrer un ResultSet con trescampos de los tipos especificados, por ese orden.

p Un iterador se asocia a una consulta de la forma:EmpIter empRow = null;#sql empRow = {SELECT empno, ename, sal FROM emp};produciéndose una correspondencia de campos pornombre.

p Un iterador posee el método next() (con idénticocomportamiento a un ResultSet) y funciones con losnombres de los campos con los que se declaró. Ej.:while (empRow.next()){

System.out.print(empRow.empno()+”-“);System.out.print(empRow.ename()+”-“);System.out.println(empRow.sal()+”-“);

}

p El iterador debe cerrarse con close():empRow.close();

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -9-

Capítulo 4: SQLJ.

Ejemplo deSELECT con resultado múltiple

import java.sql.*;import oracle.sqlj.runtime.*;public class SelectCompuesto{

public static void main(String[] args)throws SQLException {Oracle.connect(SelectCompuesto.class, "connect.properties");#sql iterator EmpIter (int empno, String ename, double sal);EmpIter empRow = null;#sql empRow = {SELECT empno, ename, sal FROM emp};while (empRow.next()){

System.out.print(empRow.empno()+"-");System.out.print(empRow.ename()+"-");System.out.println(empRow.sal()+"-");

}empRow.close();Oracle.close();

}}

p Nótese que si algún salario en NULL, esto da unerror. Para evitar este problem, basta con sustituir eldouble por Double:#sql iterator EmpIter (int empno, String ename, Double sal);

p Si se desea gestionar la excepciónSQLNullException, hay que importar el paquetesqlj.runtime.*

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -10-

Capítulo 4: SQLJ.

Ejemplo deSELECT con resultado múltiple

p Si interesa obtener los registros resultantes de unSELECT en variables Java, se puede usar un iteradoranónimo y la sentencia FETCH ... INTO. Bastaríacon poner el trozo de código:

#sql iterator EmpIter (int, String, Double);EmpIter empRow = null;int empno=0;String ename=null;Double sal=null;#sql empRow = {SELECT empno, ename, sal FROM emp};while (true){

#sql {FETCH :empRow INTO :empno, :ename, :sal};if (empRow.endFetch()) break;System.out.print(empno+"-");System.out.print(ename+"-");System.out.println(sal+"-");

}empRow.close();

p Una declaración de la forma:#sql iterator EmpIter (int empno, String ename, Double sal);crea una clase EmpIter que hereda desqlj.runtime.ResultSetIterator, que incluye lasfunciones empno(), ename() y sal() para recuperar losdatos. Pueden añadirse modificadores de clase:#sql public static iterator EmpIter (int, String, Double);

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -11-

Capítulo 4: SQLJ.

Iteradores scrollablep Permiten recorrer aleatoriamente el resultado de unSELECT. Se declaran de la forma:#sql iterator EmpIter implements sqlj.runtime.Scrollable (int empno,String ename, double sal);

p Un iterador scrollable puede hacer uso de:isBeforeFirst(), beforeFirst()isFirst(), first(), isAfterLast(), afterLast()isLast(), last(), next(), previous(), absolute(int),relative(int), al igual que un ResultSet scrollable. También puedeusar setFetchDirection(int), donde el parámetro setoma de una de las constantes de la clasesqlj.runtime.ResultSetIterator: FETCH_FORWARD yFETCH_REVERSE.

p Si el ResultSet es anónimo se puede hacer uso de:#sql { FETCH NEXT FROM :iter INTO :x, :y, :z };#sql { FETCH PRIOR FROM :iter INTO :x, :y, :z };#sql { FETCH FIRST FROM :iter INTO :x, :y, :z };#sql { FETCH LAST FROM :iter INTO :x, :y, :z };#sql { FETCH RELATIVE :(valor) FROM :iter INTO :x, :y, :z };#sql { FETCH ABSOLUTE :(valor) FROM :iter INTO :x, :y, :z };

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -12-

Capítulo 4: SQLJ.

Ejemplo de iteradores scrollablep El siguiente ejemplo recorre los registros de atráshacia adelante.

import java.sql.*;import oracle.sqlj.runtime.*;import sqlj.runtime.*;public class SelectScrollable{

public static void main(String[] args)throws SQLException {Oracle.connect(SelectScrollable.class, "connect.properties");#sql iterator EmpIter implements Scrollable

(int empno, String ename, Double sal);EmpIter empRow = null;#sql empRow = {SELECT empno, ename, sal FROM emp};// La siguiente línea se puede quitar// Es sólo a efectos de eficiencia en el cursor creadoempRow.setFetchDirection(

ResultSetIterator.FETCH_REVERSE);empRow.afterLast();while (empRow.previous()){

System.out.print(empRow.empno()+"-");System.out.print(empRow.ename()+"-");System.out.println(empRow.sal()+"-");

}empRow.close();Oracle.close();

}}

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -13-

Capítulo 4: SQLJ.

Ejemplo con scrollable anónimop El ejemplo anterior con scrollable anónimo(correpondencia de campos por posición) quedaría:

import java.sql.*;import oracle.sqlj.runtime.*;import sqlj.runtime.*;public class SelectScrollableAnonimo{

public static void main(String[] args)throws SQLException {Oracle.connect(SelectScrollableAnonimo.class, "connect.properties");#sql iterator EmpIter implements Scrollable

(int, String, Double);EmpIter empRow = null;int empno=0;String ename=null;Double sal=null;#sql empRow = {SELECT empno, ename, sal FROM emp};// La siguiente línea se puede quitar// Es sólo a efectos de eficiencia en el cursor creadoempRow.setFetchDirection(

ResultSetIterator.FETCH_REVERSE);#sql {FETCH LAST FROM :empRow

INTO :empno, :ename, :sal};while (!empRow.isBeforeFirst()){

System.out.print(empno+"-");System.out.print(ename+"-");System.out.println(sal+"-");#sql {FETCH PRIOR FROM :empRow

INTO :empno, :ename, :sal};}empRow.close();Oracle.close();

}}

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -14-

Capítulo 4: SQLJ.

Sensibilidad yControl de transacciones

p Por defecto, el resultado de un SELECT SQLJ es uniterador insensible a los cambios en los datos. Estosepuede cambiar declarando la clase del iterador de laforma:#sql public static MyScrIter implements sqlj.runtime.Scrollable

with (sensitivity=SENSITIVE) (String ename, int empno);

p En SQLJ el auto commit está desactivado pordefecto.

p Para activarlo es necesario obtener el contexto pordefecto y, a partir de él, obtener un objeto Connectional que hacerle un setAutoCommit(true):cntxt.getConnection().setAutoCommit(true);

p Como ya se comentó, estando el auto commit afalse, si se cierra el contexto sin hacer un COMMIT,entonces se hace un ROLLBACK de la últimatransacción.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -15-

Capítulo 4: SQLJ.

DDL y DMLp A continuación se muestra un ejemplo compuesto.import java.sql.*;import oracle.sqlj.runtime.*;import sqlj.runtime.*;public class DDLDML{

public static void main(String[] args)throws SQLException {Object array[][]= {

{new Integer(123), "Gustavo"},{new Integer(567), "Federico"},{new Integer(123), "Ismael"},{new Integer(186), "Iván"},{new Integer(633), "Tadeo"},

};final int ID = 0,

NOMBRE = 1;Oracle.connect( "jdbc:oracle:thin:@localhost:1521:oracle",

"scott", "tiger");try{

#sql { create table PRUEBA (ID NUMBER(5) PRIMARY KEY, NOMBRE VARCHAR2(35)) };

}catch(SQLException x){System.out.println("Tabla ya creada.");

};for(int i=0; i<array.length; i++){

int existe;#sql { select count(*) into :existe from PRUEBA

where ID = :(array[i][ID]) };if (existe > 0) continue;#sql { insert into PRUEBA

VALUES(:(array[i][ID]), :(array[i][NOMBRE])) };}#sql { COMMIT };#sql iterator PruebaIt (int id, String nombre);PruebaIt pruebaRow=null;#sql pruebaRow = {select ID, NOMBRE from PRUEBA};while (pruebaRow.next()){

System.out.print(pruebaRow.id()+"-");System.out.println(pruebaRow.nombre()+"-");

}pruebaRow.close();#sql {drop table PRUEBA};Oracle.close();

}}

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -16-

Capítulo 4: SQLJ.

Cursores anidadosp Como sabemos, una sentencia como:SELECT nombre, CURSOR(

SELECT nombre, apellidos FROM empleados WHERE departamentos.codigo = empleados.codigo_departamento)

FROM departamentos;produce un resultado maestro/detalle.

p Esto puede conseguirse en SQLJ declarando uniterador para el detalle, y otro para el maestro. Eliterador maestro contendrá un campo de tipo iteradordetalle.

p Para que el iterador maestro vea al detalle, lositeradores deben declararse fuera de la clase principal.Para ello se añaden los modificadores de claseconvenientes: private y public donde convenga.

p Nótese la cláusula AS para poder referencias aliterador detalle.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -17-

Capítulo 4: SQLJ.

Ejemplo de cursores anidadosp El ejemplo anterior quedaría:import java.sql.*;import oracle.sqlj.runtime.*;public class MaestroDetalle{#sql public static iterator EmpIter (String ename, Double sal);#sql private static iterator DptIter (String dname, EmpIter empleados);

public static void main(String[] args)throws SQLException {Oracle.connect(MaestroDetalle.class, "connect.properties");EmpIter empRow = null;DptIter dptRow = null;#sql dptRow = { SELECT dname, CURSOR(

SELECT ename, salFROM emp WHERE dept.deptno = emp.deptno)

AS empleadosFROM dept};

while (dptRow.next()){System.out.println(dptRow.dname());empRow = dptRow.empleados();while (empRow.next()){

System.out.print(empRow.ename()+"-");System.out.println(empRow.sal());

}empRow.close();

}dptRow.close();Oracle.close();

}}

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -18-

Capítulo 4: SQLJ.

Procedimientos PL/SQLp Un procedimiento PL/SQL se llama con CALL, deigual forma que desde PL/SQL. Ej.:#sql {CALL DBMS_OUTPUT.PUT_LINE(‘Cursillo’)};

p Nótese cómo un PUT_LINE sólo funcionará en elcaso de un programa SQLJ metido comoprocedimiento almacenado. Esto se verá más adelante.

p Los parámetros OUT o IN OUT deben ser variablesJava.

p El resultado de una función se obtiene de la forma:#sql hSal = {VALUES (funcionPL_SQL(parámetros))};o bien:#sql { SET :hSal = funcionPL_SQL(parámetros) };

p La utilización de SET con respecto a VALUEStiene la ventaja de que permite evaluar expresionescompletas (no sólo funciones simples), así comoevaluar variables pre-construidas. Ej.:import java.sql.*;import oracle.sqlj.runtime.*;public class LlamadaAFuncion{

public static void main(String[] args) throws SQLException {Oracle.connect(LlamadaAFuncion.class, "connect.properties");Date fecha=null;#sql {SET :fecha = sysdate};System.out.println("La fecha de Oracles es " + fecha);

}}

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -19-

Capítulo 4: SQLJ.

SQLJ dentro deprocedimientos PL/SQL

p El SQLJ puede ejecutarse dentro de una base dedatos como cualquier procedimiento o funciónalmacenada no SQLJ.

p La única diferencia es que no hay que crear ningúntipo de contexto ni conexión. Se trabaja directamentecon la sesión del que ejecuta el procedimientoalmacenado. Ej.:

import java.sql.*;import oracle.sqlj.runtime.*;public class PrimerProcedimientoAlmacenado{

public static void imprimir() throws SQLException {#sql {CALL DBMS_OUTPUT.ENABLE(2000)};#sql {CALL DBMS_OUTPUT.PUT_LINE('Cursillo')};

}} c:\>loadjava -user scott/tiger@oracle -oci8 -resolve

PrimerProcedimientoAlmacenado*.class SQL> CREATE OR REPLACE PROCEDURE IMPRIMIR AS

LANGUAGE JAVA NAME 'PrimerProcedimientoAlmacenado.imprimir()';

p Nótese la necesidad de hacer un SETSERVEROUTPUT ON para ver el texto en pantalla.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -20-

Capítulo 4: SQLJ.

VARRAYp SQL permite trabajar con arrays de longitudlimitada pero indefinida:CREATE TYPE T_DATOS AS VARRAY(10) OF VARCHAR2(35);

p Se pueden crear campos de este tip de la forma:CREATE TABLE INFO(ID NUMBER,DATOS T_DATOS);

p Las inserciones serían:

INSERT INTO INFO VALUES(1, T_DATOS('UNO', 'DOS', 'TRES', 'CUATRO'));

p Y la selección, tan sencilla como:

SELECT * FROM INFO;

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -21-

Capítulo 4: SQLJ.

VARRAYp Para trabajar con un VARRAY con SQLJ hay quecrear una clase wrapper. Lo mejor es hacerlo con lautilidad jpub.exe (Jpublisher). Ej.:jpub -sql=T_DATOS -user=scott/tiger@oracleque genera T_DATOS.java

p El fichero Java generado posee las funciones:Constructor sin parámetros.getArray() que en nuestro caso devuelve String[]setArray(String[])length()getElement(int) devuelve el elemento indicado: StringsetElement(String, int)Todas las operaciones pueden generar SQLException.

p En general, jpub permite crear clases Java wrapperde cualquier tipo definido en Oracle. Esto se verá másadelante, al estudiar Jdeveloper.

p jpub posee los modificadores:-usertypes-numbertypes-lobtypes-builtintypesque pueden valoer oracle ó jdbc según se quiera quelas clases generadas hereden en base a la bibliotecaestándar (JDBC) o a la deOracle.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -22-

Capítulo 4: SQLJ.

Consultas a VARRAYp Un ejemplo de consulta sería (una vez generado elwrapper):

import java.sql.*;import oracle.sqlj.runtime.*;public class ConsultaVARRAY{

public static void main(String[] args)throws SQLException {

Oracle.connect(Primer.class, "connect.properties");#sql iterator InfoItClass (Integer id, T_DATOS datos);InfoItClass infoIt=null;#sql infoIt = {SELECT * FROM INFO};while(infoIt.next()){

System.out.println(infoIt.id());for(int i=0;i<infoIt.datos().length(); i++)

System.out.println("\t"+infoIt.datos().getElement(i));}

}}

p Mucho cuidado porque para que esto funcione esnecesario incluir en el CLASSPATH la biblioteca\oracle\ora92\jdbc\lib\nls_charset12.jar. Si no se poneesa librería, los String salen en Hexadecimal debido alas conversiones de los juegos de caracteresnacionales.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -23-

Capítulo 4: SQLJ.

Inserción en VARRAYp Un ejemplo de inserción sería:

import java.sql.*;import oracle.sqlj.runtime.*;public class InsercionVARRAY{

public static void main(String[] args)throws SQLException {

Oracle.connect(Primer.class, "connect.properties");T_DATOS datos = new T_DATOS();datos.setArray(new String[]{"Alfa", "Beta", "Gamma"});#sql {INSERT INTO INFO VALUES (2, :datos)};#sql {COMMIT};

}}

p Nótese la existencia de un constructor sinparámetros de la clase T_DATOS.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -1-

Capítulo 5: JDeveloper.

Capítulo 5JDeveloper

p Jdeveloper es un potente entorno gráfico que facilitael trabajo con Java y Oracle.

p Permite construir programas SQLJ y guardarloscomo procedimientos almacenados, con poco esfuerzo.

p Permite las construcción de componentes OC4J queson algo así como envolturas a los componentesrelacionales de la base de datos.

p Permite convertir estos componentes a distintosframeworks: OAS, J2EE, JSP, etc.

p Un framework es una filosofía de construcción deprogramas Java que suele acceder a una base de datos.

p Un framework se apoya en componentespropietarios, por lo que es conveniente hacer uso deherramientas visuales que los construyanautomáticamente.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -2-

Capítulo 5: JDeveloper.

Instalaciónp Jdeveloper se puede descomprimir (en esto consistela instalación) en cualquier directorio que no seaORACLE_HOME.

p El fichero básico de configuración es:<jdev_install>\jdev\bin\jdev.conf

p Hay que asegurarse de que este fichero contiene dosentradas:

< Una que indica donde está el JDK. Ej.:SetJavaHome e:\j2sdk1.4.2

< Y otra que indica qué JVM se va a usar. Esconveniente hacer uso de la JVM de Oracle(OJVM) que está optimizada para Jdeveloper.Ej.:

SetJavaVM ojvmpero también se puede hacer:

SetJavaVM hotspot

p Para hacer uso de la OJVM hay que configurar suacceso, indicándole dónde está el JDK:<jdev_install>\jdev\bin\InstallOJVM.bat e:\j2sdk1.4.2

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -3-

Capítulo 5: JDeveloper.

Ejecuciónp El fichero de ejecución de Jdeveloper paraWindows es:

<jdev_install>\jdev\bin\jdevw.exe

p Una vez conectados a Jdeveloper, éste tiene lasiguiente apariencia:

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -4-

Capítulo 5: JDeveloper.

Filosofía estructuralp Jdeveloper estructura el trabajo en aplicacionescompletas, llamadas workspaces.

p Un workspace puede estar formado por uno o másproyectos. Un proyecto es simplemente un conjunto deficheros relacionados para un propósito concretodentro de una aplicación.

p Básicamente hay dos tipos de workspace: Java yweb. Nosotros nos centraremos en los Java.

p Una vez creado un workspace, es posible crear ensu interior tantos proyectos como se quiera.Trabajaremos con dos tipos de proyectos: BussinessComponents y Java Application.

p Finalmente, a un proyecto se le añadirán losficheros concretos que lo componen.

p Jdeveloper incorpora asistentes para la creación denumerosos componentes, aunque éstos tambiénpueden construirse manualmente.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -5-

Capítulo 5: JDeveloper.

Ejecución de un proyectop Para ejecutar un proyecto es necesario depositarloen un destino (deployment).

p Esto es así, porque a estos niveles, la ejecución notiene porqué ser en local, sino que puede ser remotahaciendo uso de distintos esquemas de ejecución:J2EE, OAS, JSP, local, procedimientos almacenados,etc.

p Sea cual sea el destino, hay que establecer unaconexión a él. Lo normal es crear, al menos, unaconexión a la base de datos Oracle con la que se va atrabajar.

p Para ello, el panel de navegación tiene una pestañaConnections donde es posible crear los distintos tiposde conexiones.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -6-

Capítulo 5: JDeveloper.

Deposiciónp Si, por ejemplo, se va a crear un procedimiento almacenado,lo primero que hay que hacer es crear una conexión que accedaal esquema que los va albergar.

p A continuación hay que seleccionar en el proyecto, la creaciónde un New -> Deployment profile. A continuación escogeríamosla opción Loadjava...

p Por último, seleccionamos los ficheros a depositar.

p Una vez finalizada esta fase, en el perfil de deposición creadohay que seleccionar qué métodos se quieren cargar y con quewrapper PL/SQL. El wrapper lo crea automáticamenteJdeveloper.

p Finalmente, se haría la deposición con la conexión que sequiera.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -7-

Capítulo 5: JDeveloper.

Caso prácticop Vamos a colocar el siguiente código SQLJ dentrodel esquema de scott.

import java.sql.*;import oracle.sqlj.runtime.*;

public class PrimerSqljJDeveloper {public static void imprimir(String arg) throws SQLException {

#sql {CALL DBMS_OUTPUT.ENABLE(2000)};#sql {CALL DBMS_OUTPUT.PUT_LINE(:arg)};

}}

p Los pasos exactos que hay que seguir son:1.- Crear una conexión2.- Crear un área de trabajo.3.- Crear un proyecto.4.- Indicar las librerías del proyecto.5.- Añadir un fichero SQLJ.6.- Crear un perfil de deposición.7.- Configurar los procedimientos PL/SQL.8.- Ejecutar la deposición.9.- Comprobar el procedimiento desde SQL*Plus o SQL*Worksheet.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -8-

Capítulo 5: JDeveloper.

Pasos (I)p Para crear la conexión, pulsar la pestañaConnection del Navigator. Database->Botónderecho->New Connection.

p La conexión debe ser Oracle(JDBC) y el nombre:OracleJDBC_SID.

p Ahora hay que escoger el esquema de usuario, eltipo de driver a usar (Thin u OCI8), así como la basede datos a la que conectarse.

p Comprobar que la conexión es satisfactoria. Si no,comprobar nombre de usuario, contraseña y sid.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -9-

Capítulo 5: JDeveloper.

Pasos (II)p Para crear el área de trabajo, pulsar Applications ->Botón derecho->New Application Workspace.

p Automáticamente se ha creado el proyecto Client.Renombrar Client como SqljPRJ: Seleccionar Client.File -> Rename

p Antes de añadir el fuente SQLJ es necesario ajustarel CLASSPATH del proyecto.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -10-

Capítulo 5: JDeveloper.

Pasos (III)p Para añadir librerías a SqljPRJ: SeleccionarSqljPRJ -> Botón derecho -> Project properties ->Profiles -> Development -> Libraries.

p Aquí crearemos dos librería nuevas:GeneralJDBC que contendrá los JAR:

<ORAHOME>\jdbc\lib\classes12.jar<ORAHOME>\jdbc\lib\ojdbc.jar<ORAHOME>\jdbc\lib\nls_char12.jar

GeneralSQL que contendrá los JAR:<ORAHOME>\sqlj\lib\translator.jar<ORAHOME>\sqlj\lib\runtime12.jar

p Estas librerías deberán estar añadidas a la lista deseleccionadas, junto con JDeveloper Runtime.

p Para añadir ficheros a SqljPRJ: Seleccionar SqljPRJ-> Botón derecho -> New -> General -> Simple Files-> File.

p Éste será el fichero SQLJ mostrado anteriomente.Su nombre debe coincidir con el de la clase quecontiene, y debe tener extensión sqlj.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -11-

Capítulo 5: JDeveloper.

Pasos (IV)p Una vez escrito el código del fichero SQLJ, hayque crear el perfil de deposición: SeleccionarSqljPRJ -> Botón derecho -> New -> General ->Deployment Profiles -> Loadjava and Java StoredProcedures.

p Si no aparece Loadjava..., seleccionar Filter by: All

technologies.

p Aceptar las opciones que se proponen. Se le puedecambiar el nombre al perfil, si así se desea.

p En el navegador se creará una pestaña Resourcesque contendrá al perfil de deposición.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -12-

Capítulo 5: JDeveloper.

Pasos (V)p Sobre el perfil de deposición: Botón derecho ->Add Stored Procedure -> imprimir -> Settings.

p Con esto, estamos diciendo que vamos a crear unwrapper PL/SQL para la función imprimir del SQLJ.

p Una vez hecho esto, ya sólo queda realizar ladeposición. Sobre el perfil de deposición -> Botónderecho -> Deploy to -> OracleJDBC_SID:

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -13-

Capítulo 5: JDeveloper.

JPublisherp Jdeveloper permite ejecutar Jpublisher desde unasistente.

p A través de una conexión es posible ver todos loselementos de un usuario.

p Si el objeto sobre quien se ejecuta el Jdeveloper esun registro, entonces se crean dos ficheros: uno .sqljque representa al objeto en sí, y otro .java querepresenta a una referencia a dicho objeto.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -14-

Capítulo 5: JDeveloper.

Filosofía OC4Jp Jdeveloper permite el desarrollo de aplicaciones quepueden ser depositadas sin modificación en diversasplataformas: OC4J, J2EE, etc.

p OC4J es una envoltura sobre las tablas y clavesforáneas de la base de datos.

p Sobre esta envoltura se construye una aplicación, abase de formularios.

p Las aplicaciones se pueden ejecutar en diferentesentornos, según la deposición que se haga. Nosotrosveremos EJB sobre navegadores web y aplicacionesindependientes.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -15-

Capítulo 5: JDeveloper.

Capa de negociop Los componentes que forman la capa de negocioson:

p Objetos Entidad: < Se corresponde con una tabla o vista de la capa de datos.< Gestiona la interacción con la base de datos, incluidos los

buffer necesarios.< Están formados por atributos.< Implementa la validación de datos. Para ello puede ser

necesario crear Dominios.< Realmente son clase de Java, luego las reglas de negocio se

definen en forma de métodos.

p Asociaciones:< Se corresponde con una clave foránea< Se utilizan para representar las relaciones maestro-detalle

entre dos objetos entidad.< Una asociación es bidireccional.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -16-

Capítulo 5: JDeveloper.

Capa de manipulaciónp Los componentes que forman la capa demanipulación son:

p Objetos vista:< Contiene un subconjunto de los datos referenciadospor un

objeto entidad.< Visualiza los datos correspondientes a una consulta SQL.< Permite hacer filtrados y ordenación de los datos.< Puede hacer referencia a atributos de un objeto entidad, así

como a atributos calculados.< Permiten la manipulación: inserción, eliminación y

actualización.< Se implementa como un JavaBean.

p Enlaces de vistas:< Define un enlace maestro-detalle entre dos objetos vista.< Es un objeto unidireccional que coordina la recuperación de

los datos pertinentes a un maestro.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -17-

Capítulo 5: JDeveloper.

Creación de una aplicaciónOC4J

p Una vez creado el correspondiente proyecto(DeptEmpPRJ), hay que crear la capa de negocio:p

En este punto, un asistente nos ayudará aseleccionarlas tablas origen para crear los objetos entidad, asícomo los objetos vista por defecto.

p Las asociaciones y enlacestambién se crean. Puede serconveniente cambiarles el nombre.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -18-

Capítulo 5: JDeveloper.

Módulo de aplicación OC4Jp Con el asistente anterior también se crea un módulo de aplicación.

p El módulo de aplicación es la última fase de la capa intermedia(middle-tier).

p Representa un conjunto de relaciones entre objetos vista. Un mismomódulo de aplicación puede contener diferentes composiciones maestro-detalle. Cada composición hace uso de una instancia de un objeto vistaconcreto.

p Las aplicaciones clientes (Frames, JSP, etc.) acceden a un módulo deaplicación a través de JNDI (ya sea en modo local o en modo EJB, segúnla configuración elegida).

p A partir del módulo de aplicación, las aplicaciones cliente acceden ala instancia de objeto vista que se quiera: clase ViewObject.

p La clase ViewObject es muy completa y permite recorrer los registrosmediante, a su vez, la clase Row.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -19-

Capítulo 5: JDeveloper.

Test básico de unmódulo de aplicación OC4J

p La aplicación puede ser testada con la configuraciónpor defecto: Botón derecho sobre AplicacionDeptEmp-> Configurations ó Test

p Es conveniente establecer un paquete para laaplicación, y otro distinto para los clientes.

p Los clientes generados automáticamente hacen usode unos ficheros XML para realizar la correspondenciaentre los campos del Frame y los atributos de unobjeto vista.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -20-

Capítulo 5: JDeveloper.

Creción de un clientep Con el test anterior sólo se puede probar laaplicación desde dentro del Jdeveloper.

p Para poder depositar todo el resultado en algún sitioy poderlo ejecutar, es necesario crear una capa cliente:p Esto nos llevará a un asistente que nos permitirá

crear un formulario parecido al que se generó en el testanterior.

p Previamente se creará un modelo de datos queaccede a una configuración concreta de una aplicación.El formulario se puede modificar y ejecutar:

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -21-

Capítulo 5: JDeveloper.

Ejecución de un proyectop Un proyecto se puede ejecutar modificando suspropiedades y cambiando el punto de entrada:

p Así, el botón de ejecución ( ) ejecutará el ficheroque se indique.

p Nótese la enorme cantidad de libreríasreferenciadas: Libraries.

p La sentencia que desencadena la ejecución puedeverse en el log del Jdeveloper. Esta sentencia puedeusarse para lanzar el programa de forma independientedel JDeveloper.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -22-

Capítulo 5: JDeveloper.

Deposiciones de unaaplicación OC4J

p Una vez creada una aplicación, y la capa cliente sepueden hacer distintas deposiciones para ponerla enejecución:

p La deposición Simple Archive Files permite generarficheros JAR que aglutinan todo nuestro proyecto.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -23-

Capítulo 5: JDeveloper.

El servidor J2EEp Jdeveloper incorpora un contenedor/servidorJ2EE para suministrar Enterprise Java Beans.

p Como fase de instalación, sólo hay que darle unaclave al usuario admin:<jdev_install>\j2ee\home>java -jar oc4j.jar -installlo que pedirá clave y confirmación.

p El servidor se arranca con:<jdev_install>\jdev\bin>start_oc4j.bat

p Y se para con:<jdev_install>\jdev\bin>stop_oc4j admin manager

p En todo este proceso quizás sea necesario darle unvalor a la variable de entono JAVA_HOME.

p Cuidado porque los puertos de conexión hancambiado de una versión a otra del servidor OC4J deJ2EE.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -24-

Capítulo 5: JDeveloper.

Deposición en forma deEnterprise JavaBeans

p Una vez arrancado el servidor, se debe crear unaconexión a un servidor de aplicaciones.

p El tipo de conexión es Standalone OC4J.

p Ahora podemos comenzar una deposición EJBSession Beans. Podemos escoger todas las opcionespor defecto. Haremos una deposición del únicomódulo de aplicaciones que hemos creado.

p Una vez creado el perfil de la deposición, podemosejecutarla seleccionando la opción:

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -25-

Capítulo 5: JDeveloper.

Deposición en forma deEnterprise JavaBeans

p Lo anterior crea una serie de ficheros JAR y losdeposita en el contenedor J2EE que además los sirve.

p Ahora es posible testar la aplicación, teniendo encuenta que hay que seleccionar un nuevo tipo deconexión creada automáticamente al haber creado unnuevo perfil de deposición.

p Aparentemente el resultado es el mismo que enLocal, pero se está trabajando con JavaBeans.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -26-

Capítulo 5: JDeveloper.

Deposición en JSPp La creación de páginas JSP se ha modificado en laversión 10g de Jdeveloper.

p Hay que crear un esquema de flujo Struts que indicacómo se pasa de una página a otra y qué ejecucióndesencadena la pulsación de cada botón.

p Seguir los pasos que se indican en el documentoadjunto.

p Cuidado. En lugar de crear las páginas JSP desde elmodelo Struts, es mejor crearlas fuera y arrastrarlasdespués al modelo Struts. También se puedemodificar el fichero modelo visual que está en lacarpeta models.

p Cuidado ya que hay que meter la barra denavegación dentro del formulario de datos.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -27-

Capítulo 5: JDeveloper.

Propiedades de un objeto entidad

p Cada objeto entidad tiene asociada una clase Java que permitegestionar cada registro. Además hay un fichero XML que indica suscaracterísticas dentro de Jdeveloper.

p Si es necesario modificar el comportamiento de la clase Java, es mejorhacerlo a través del editor de Jdeveloper, quien modifica la clase Java ala vez que actualiza su fichero XML de control.

p Con este método se pueden añadir mecanismos de validación en lacapa de negocio, como puede verse en la figura. Cualquier vista sobreeste objeto entidad se verá forzada a cumplir la validación, así comocualquier aplicación.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -28-

Capítulo 5: JDeveloper.

Propiedades de unobjeto vista

p Un objeto vista está formado por una sentenciaSELECT. Cada columna de dicha SELECT produceun campo de la vista.

p Además, es posible añadir más campos. Estoscampos pueden tener valores calculados.

p Los campos se calculan una sola vez cuando secarga el cursor por la consulta.

p Para actualizar los campos calculados es necesariorealizar una nueva consulta en tiempo de ejecución.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -29-

Capítulo 5: JDeveloper.

Creación de un clientemanualmente

p Para poder crear un cliente de forma manual hayque comprender bien el mecanismo OC4J.

p Para no desvirtuar la filosofía OC4J, es necesariocrear los componentes de la capa de negocio, los de lacapa de presentación y el módulo de aplicación:< La capa de negocio esige crear los objetos entidad con las reglas de

validación, así como las asociaciones necesarias.< La capa de presentación exige crear los objetos vista junto con los

campos calculados que se requieran< El módulo de aplicación será el servidor de nuestra aplicación

cliente, y debe contener instancias de los objetos vista. Estasinstancias estarán convenientemente relacionadas mediante enlacesmaestro-detalle.

p La aplicación cliente debe:< Especificar un entorno mediante una tabla hash queindique a qué

servidor JNDI nos vamos a conectar.< Crear un contexto basado en ese entorno.< Buscar la clase del módulo de aplicaciones deseado mediante el

localizador JNDI.< Crear una instancia del módulo de aplicaciones.< Establecer una conexión.< A partir de dicha instancia obtener los objetos vista a manipular.< Manipular la vista.< Cerrar la conexión.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -30-

Capítulo 5: JDeveloper.

Cómo conectar con un módulode aplicaciones

p El siguiente bloque de código permite conectar conun módulo de aplicaciones BlobModule:...private Hashtable env = new Hashtable(10);private Context ic;private ApplicationModuleHome home;private ApplicationModule appMod;private BlobModuleImpl finalModule;...try{

env.put( Context.INITIAL_CONTEXT_FACTORY, JboContext.JBO_CONTEXT_FACTORY);

env.put( JboContext.DEPLOY_PLATFORM, JboContext.PLATFORM_LOCAL);

ic = new InitialContext(env);home = (ApplicationModuleHome)

ic.lookup("bcpackage.BlobModule"); appMod = home.create();

appMod.getTransaction().connect("jdbc:oracle:thin:@localhost:1521:oracle","galvez", "contraseña");

finalModule = (bcpackage.BlobModuleImpl) appMod;}catch(NamingException x){

x.printStackTrace();}

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -31-

Capítulo 5: JDeveloper.

Búsqueda del módulo de aplica-ciones y obtención de la vista

p El nombre del módulo de aplicaciones que se ha de buscar en elservidor JNDI aparece en la información de configuración del módulode aplicaciones (frase en rojo del código anterior):

p Una vez conseguido el módulo de aplicaciones, hay que obtener unainstancia del mismo, y conectarse.

p Por último, hay que realizar un cast para poder acceder a las instanciasde objetos vista que contiene (frase azul del código anterior).

p A la vista se accede convo = finalModule.getDeptView1();aunque también es posible no hacer el cast y acceder convo = finalModule.findViewObject("DeptView1");pero esto último podría producir errores en ejecución.

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -32-

Capítulo 5: JDeveloper.

Acceso a la vistap El acceso a la vista permite realizar operacionescon la misma (ver la extensa claseoracle.jbo.server.ViewObjectImpl)

p El siguiente bloque de código permite visualizar elprimer registro, si existe:private ViewObject vo;private DeptViewRow row;...

vo = finalModule.getDeptView1();row = (DeptViewRow)vo.first();if (row==null) frame.añadirTexto("No hay registros");else{

frame.añadirTexto(""+row.getDeptno());frame.añadirTexto(row.getDname());frame.añadirTexto(row.getLoc());

}appMod.getTransaction().disconnect();

p La variavle row también se puede definir de tipoRow, de manera que los atributos se pueden recuperarde la forma:row.getAttribute("Deptno")lo cual es propenso a errores en tiempo de ejecución.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -33-

Capítulo 5: JDeveloper.

Creación de la aplicacióncompleta

p Para poner todo esto en funcionamiento, basta crearuna aplicación con una ventana Java y un cuadro detexto en el que visualizar los datos.

p A continuación se puede escribir el código indicadoanteriormente, en cualquier lado, p.ej., en el propioconstructor (aunque no es lo suyo) y ver el resultado:

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -34-

Capítulo 5: JDeveloper.

La clase ViewObjectImplp Algunas funciones interesantes de la claseViewObjectImpl son:getAllRowsInRange() que devuelve un Row[] que contiene todas lasRows accesibles por la vista.findByKey(Key key, int maxNumOfRows) que devuelve un Row[] contodas las Rows que cumplen la clave (Key) pasada como parámetro. UnaKey se construye con new Key(new Object[] { keyValue1, keyValue2,...});, donde los keyValue suelen ser String. Ejemplo:private DeptViewRow row;private Row[] rows;...

rows = vo.findByKey(new Key(new Object[] { "20" }),1);if (rows.length==0) frame.añadirTexto("No hay registros");else{

row = (DeptViewRow)rows[0];frame.añadirTexto(""+row.getDeptno());frame.añadirTexto(row.getDname());frame.añadirTexto(row.getLoc());

}createRow() que crea y devuelve un nuevo registro vacío.insertRow() que permite insertar el registro anterior en la vista. Ejemplo:Row r = vo.createRow();r.setDeptno(110);r.setDname("HORTOFRUTICOLA");r.setLoc("ARCHIDONA");vo.insertRow(r);Esta operación invoca automáticamente al métod create() (si lo hay) delobjeto correspondiente de la capa de negocio.

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -35-

Capítulo 5: JDeveloper.

La clase ViewObjectImply la cláusula WHERE

p Un objeto ViewObjectImpl permite recuperarregistros que cumplan una cláusula WHERE:vo.getViewObject().setWhereClause("Deptno = " + valor );vo.executeQuery();vo.first();rows = vo.getAllRowsInRange();

p Esto hace que vo trabaje siempre enlazado a esacláusula WHERE. Para desenlazarlo, hacer:vo.getViewObject().setWhereClause("");

p También es posible hacer uso deparámetros:vo.setWhereClause("Deptno = :1 ");try{

vo.setWhereClauseParam(0,new oracle.jbo.domain.Number(20));} catch(java.sql.SQLException ex) {

ex.printStackTrace();}vo.executeQuery();vo.first();rows = vo.getAllRowsInRange();

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -36-

Capítulo 5: JDeveloper.

La clase Row yla gestión de transacciones

p Ya hemos visto como realizar una conexión, pero también es posiblegestionar las transacciones a través de un objeto ApplicationModule:am.getTransaction().commit();am.getTransaction().rollback();am.getTransaction().connect(jdbcConnStr, user, password);am.getTransaction().disconnect();

p A través de la clase Row, se pueden modificar directamente losatributos, sin más que hacer uso de los métodos setCampo() y luegohacer un COMMIT.

p La Clase Row posee el método remove() para eliminar registros.

p Para obtener la clase DeptViewRow o similar que herede de DeptRowes necesario decirle al objeto vista que suministre métodos al Cliente, asícomo qué métodos de Cliente debe suministrar:

SGR

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -37-

Capítulo 5: JDeveloper.

Obtención de un BLOBp El siguiente bloque de código permite visualizaruna imagen almacenada en un BLOB:

vo = finalModule.getGrandeView1();row = (GrandeViewRow)vo.first();if (row==null) this.añadirTexto("No hay registros");else{

this.añadirTexto(""+row.getId());BlobDomain b = row.getBlobData();byte[] datos = b.getBytes(1, (int)b.getLength());label.setIcon(

new ImageIcon(Toolkit.getDefaultToolkit().createImage(datos)));

}

Java y Bases de Datos (Oracle). Cursos de verano, Acción Estudiantil, 2004. -38-

Capítulo 5: JDeveloper.

Escritura de un BLOBp El siguiente código permite insertar un BLOB.

< Nótese que la tabla subyacente tiene un valor por defecto (DEFAULT)de empty_blob() para el campo BLOB.

< Además, es necesario bloquear el registro al que se va a acceder.< No es necesario hacer un setBlobData(...).

JFileChooser jfc = new JFileChooser("."); int retval = jfc.showOpenDialog(BlobFrame.this); if (retval == JFileChooser.APPROVE_OPTION) { File myFile = jfc.getSelectedFile(); Icon icon = new ImageIcon ( myFile.getAbsolutePath()); label.setIcon(icon); try{ ViewObject voDml = finalModule.getGrandeView1(); //Inserción del registro con valor empty_blob() en el campo BLOB. GrandeViewRow r = (GrandeViewRow)voDml.createRow(); int id = Integer.parseInt(texto.getText()); r.setId(new oracle.jbo.domain.Number(id)); voDml.insertRow(r); finalModule.getTransaction().commit(); // Recuperación del registro recién insertado. vo.setWhereClause(" id = " + id); vo.executeQuery(); r = (GrandeViewRow)vo.first(); // Inserción del dato de tipo BLOB. BlobDomain b = r.getBlobData(); int tamañoBuffer = b.getBufferSize(); r.lock(); OutputStream out = b.getBinaryOutputStream(); BufferedInputStream in = new BufferedInputStream(new FileInputStream(myFile), tamañoBuffer); byte[] chunk = new byte[tamañoBuffer]; while (true){ int numBytes = in.read(chunk, 0, tamañoBuffer); if (numBytes == -1) break; out.write(chunk, 0, numBytes); } in.close(); out.close(); finalModule.getTransaction().commit(); }catch (Exception x){ x.printStackTrace(); finalModule.getTransaction().rollback(); } }