Está en la página 1de 39

Programación Orientada a

Objetos

Modulo 7
JDBC

Universidad de Chile
Departamento de Ciencias de la Computación
Temario
 Streams
 El package java.io
 Streams de bytes y de caracteres
 Streams de bajo y alto nivel
 Leyendo y escribiendo
 Sockets

2
JDBC

 JDBC es una API, formada por conjunto de


clases e interfaces en el lenguaje de
programación Java, para ejecutar sentencias
SQL sobre una base de datos (externa).
 Ofrece un estándar de conexión a cualquier
base de datos disponible en el mercado.
 Permite obtener los datos en forma fácil y
cómoda en ambientes cliente-servidor a
través de Internet/Intranet.
¿Qué hace JDBC?

 Permite establecer una conexión a una


base de datos.
 Permite enviar sentencias SQL.
 Permite procesar los resultados de estas
sentencias.
 Las clases que permiten esto están en
el paquete java.sql (hay que importarlo)
Modelos de acceso a BD

 De 2 capas
Cliente  La aplicación “habla” directamente con

Aplicación la base de datos.


Java  Controlador JDBC se comunica con el

JDBC sistema específico que maneja la base


Protocolo
de datos.
BD  La base de datos puede estar en otra

máquina, con lo que el cliente se


DBMS comunica por red. Esta es la
configuración llamada cliente/servidor.
Servidor BD

5
Modelos de acceso a BD
Cliente (GUI)  De 3 capas
Navegador  Los comandos son enviados a la

Web capa intermedia de servicios, la


Protocolo HTTP cual envía sentencias SQL a la
base de datos. Ésta las procesa
Aplicación Servlets, JSP y envía los resultados de vuelta
Java en servidor a la capa intermedia, para luego
JDBC
WEB ser enviados al cliente.
 Permite un control de acceso y
Protocolo BD
de actualización.
 Provee ventajas de

DBMS
Servidor performance.
BD

6
Cargando el Driver
 Es necesario primero cargar una clase con el driver de la
base de datos (esto lo provee el vendedor de la DBMS)
 Ejemplo:
Class c =
Class.forName(“com.informix.jdbc.IfxDriver");
Calss.forName(“com.novell.sql.LDAPDriver”);
Class.forName("com.mysql.jdbc.Driver");

 Esto es particular según la base de datos que se usa


 Luego hay que crear una instancia de la clase

c.newInstance();

7
Estableciendo la Conexión

Connection con = DriverManager.getConnection (


url,login, password);

 Un objeto “Connection” representa una


conexión a una base de datos.
 La clase “DriverManager” intenta ubicar el
controlador que pueda conectarse a la base
de datos representada en la URL.

8
Conexión

 Ejemplos de URL:
 jdbc:mysql://localhost/test (para ejemplos)
 jdbc:oracle://oraserver
 jdbc:odbc:mydatabase
 jdbc:ldap://server;baseDN=baseDN;useCle
artext=true

9
...Conexión
 Sintáxis de una URL JDBC:
 jdbc:<subprotocolo>:<subnombre>
 <subprotocolo> es el nombre del
controlador o del mecanismo de conexión.
Ejemplo: odbc.
 <subnombre> es la identificación de la
base de datos. El formato varia según el
controlador especificado. Ejemplo:
//servidor:puerto/bd y parámetros

10
Ejemplo de Conexión
import java.sql.*;
import com.mysql.jdbc.*;
java.sql.Connection getConnection(String usr, String pass) {
url = "jdbc:mysql://localhost/test";
driver = "com.mysql.jdbc.Driver";
try {
Class.forName(driver).newInstance();
con = DriverDriverManager.getConnection(url, usr,pass);
return con;
} catch(Exception e2) {
System.err.println("Problems");
return null;
}
}

11
Enviando sentencias SQL

 JDBC permite enviar cualquier tipo de


sentencia SQL. Aunque ésta fuera
dependiente de la base de datos sólo
se correría el riesgo de
incompatibilidad al cambiar de base de
datos.

12
...Enviando sentencias SQL

 JDBC provee 3 clases:


 “Statement”: Este objeto es usado para
enviar sentecias SQL simples. Es creado
por el método “createStatement”.
 “PreparedStatement”: Este objeto es
usado para sentencias que requieren uno
o más parámetros. La sentencia es
precompilada y guardada para uso futuro.
 “CallableStatement”: Es usado para
ejecutar procedimientos almacenados en
la base de datos.

13
La clase Statement
 Connection con = getConnection(…);
 Statement stmt=
con.createStatement();
 En este momento la statement existe pero no
tiene una sentencia SQL para ejecutar. Esta
se puede pasar con los métodos
 executeUpdate(String), usada para

crear/modificar tablas (no hay resultados),


típicamente para create, update, delete...
 executeQuery(String) para hacer

consultas, retornan resultados en un


objeto de la clase ResultSet, típicamente
para select
14
Crear y ejecutar comando

Statement s=con.createStatement();
s.executeUpdate(“...”);
Crear tabla

s.executeUpdate(
“create libros(”+
“ id char(20),” +
“ titulo char(50),” +
“ autor char(50,)” +
“ editorial char(20),” +
“ fecha char(8),” +
“ primary key(id))”
);
Agregar fila

s.executeUpdate(
“insert into libros values(”+
“‘JA1’,’Java’,’Alvarez’,’ACME’,’20060906’)”
);

s.executeUpdate(
“insert into lectores values(”+
“’123’,’rosa’,’Blanco 2120’,’9782000’,’’)”
);

s.executeUpdate(
“insert into prestamos values(‘”+
U.leerString(“id libro?”)+ “’,’”+
U.leerString(“id lector?”)+“’ ,’20060913’)”
);
Borrar filas
s.executeUpdate(
“delete from prestamos where idLibro=’JA1’”);

s.executeUpdate(
“delete from libros where idLibro=’”+
idLIbro.getText()+
“’”
);

s.executeUpdate(
“delete from libros where fecha<’”+
U.leerString(“fecha de eliminación?”)+
“’”
);
Actualizar filas

s.executeUpdate(
“update lectores set email=’rm@hotmail.com’”
+“where id=’123’”
);

s.executeUpdate(
“update from prestamos set fecha=’20060913’”
+“where idLibro=’JA1’”
);
Retorno de excuteUpdate

• El método excuteUpdate retorna un valor


entero correspondiente al número de filas que
la sentencia SQL modificó
• Si se trataba de una creación de tablas el valor
de retorno es 0
• Si se trata de insertar una fila el valor es 1
• El resultado es interesante cuando se usa en
una sentencia SQL con la instrucción “update
tabla set campo = <expresión> where
<condicion>

19
Ejemplos de excuteQuery
 stmt.executeQuery(“select * from
alumnos “ + “where añonac = 1974”);
 Los resultados de una consulta se reciben en
un objeto de la clase ResultSet
 ResultSet rs = stmt.executeQuery(....);
 Un ResultSet se puede ver como una
enumeración de filas que representan el
resultado
 Existen métodos adecuados para recorrer los
elementos de esta enumeración y recuperar
los valores de las columnas (campos)
20
El ResultSet
ResultSet rs = stmt.executeQuery(“select
nombre where direccion like Santiago”);
while (rs.next()) {
String s = rs.getString(“nombre”);
int y = rs.getInt(“año”);
System.out.println(s+” “+y);
}
 ResultSet rs contiene una colección de filas con los
resultados de la pregunta. La instrucción next avanza
un puntero que indica en qué fila estamos
actualmente. Al principio está antes de la primera fila,
por lo cual se hace necesario ejecutar un next() para
situarse en la primera
21
Consultar tabla libros
ResultSet r=s.executeQuery(“select ...”);
ref objeto

r “cursor” Columna 1 Columna 2 ... Columna n

ResultSet r=s.executeQuery(“select* from libros”);

r “cursor” id titulo ... fecha


Consultar tabla libros
r.next() //pasar a siguiente fila
ref objeto

r Columna1 Columna2 ... Columnan


cursor

//recorrer filas
while( r.next() ){
//recuperar valor de una columna
String s=r.getString(“nombre columna”);
. . .
}
Libro(s) más recientes(s) de Java

ResultSet r=s.executeQuery(
“select * from libros where titulo like‘%Java%’”
+ ” and fecha=(select max(fecha) from libros “
+ “where titulo like‘%Java%’)”);

while(r.next())
System.out.println(
r.getString(“id”)+
r.getString(“titulo”));
Alternativamente
ResultSet r=s.executeQuery(
“select * from libros where titulo like ‘%Java%’”);
String mayor=””;
while(r.next()){
String fecha=r.getString(“fecha”);
if(fecha.compareTo(mayor)>0) mayor=fecha;
}
//posicionar antes de primera fila
r.beforeFirst(); //r.absolute(0);
//recorrer libros de Java
while(r.next())
if( r.getString(“fecha”).equals(mayor) )
System.out.println(
r.getString(“id”)+r.getString(“titulo”));
Tabla con libros prestados

s.executeUpdate(
“create prestados(id char(20), ... )”);

ResultSet r=S.executeQuery(
“select * from libros where exists”+
“(select * from prestamos “ +
“where idLibro=libro.id)”);

while(r.next())
s.executeUpdate(
“insert into prestados values(‘”+
r.getString(“id”) + “’,’”+
...
);
Prob. Enviar un e-mail a los lectores morosos al día de hoy
que diga “el libro de título X debió devolverlo el Y”

Nota. Suponga que existe el método U.enviar de encabezamiento:


void enviar(String email, String mensaje)
//obtener lectores morosos
ResultSet r1=S.executeQuery(
“select * from prestamos where fecha<’20060911’”);
while(r1.next()){
//obtener email de lector
ResultSet r2=S.executeQuery(
“select email from lectores where id = ‘”+
r1.getString(“idLector”) + “’”);
r2.next();
//obtener titulo del libro
ResultSet r3=S.executeQuery(
“select titulo from libros where id = ‘”+
r1.getString(“idLibro”) + “’”);
r3.next();
//enviar mensaje
U.enviar(r2.getString(“email”),
“el libro “+r3.getString(“titulo”)+
“debio devolverlo el “+r1.getString(“fecha”));
}
Solución 2. Con join

ResultSet r=S.executeQuery(
“select libros.titulo, “ +
“ lectores.email, “ +
“ prestamos.fecha “ +
“from prestamos, lectores, libros “+
“where prestamos.fecha < ‘20060911’” +
“ and prestamos.idLibro = libros.id “+
“ and prestamos.idLector = lectores.id”
);
while(r.next())
U.enviar(r.getString(“lectores.email”),
“el libro “+r.getString(“libros.titulo”)+
“debio devolverlo el “ +
r.getString(“prestamos.fecha”)
);
La instrucción getXXX

 Se puede usar con 2 tipos de


parámetros:
 getXXX(“nombre de columna en la tabla”)
ej getString(“nombre”)
 getXXX(número de columna en la tabla) ej
getString(1)
 getXXX trata de leer lo que hay en la
columna y convertirlo al tipo Java
especificado en XXX

30
La instrucción getXXX
 Hay veces en que si bien, el tipo SQL no es el
mismo que el tipo XXX una conversión es posible
sin problemas (por ejemplo, con getString y
getObject se puede recuperar sin problemas
cualquier cosa)
 Otras, en que la conversión es posible pero con
pérdida de información o con posible problema de
formateo (ej getByte para un numeric o un
longvarchar
 Otras, es simplemente imposible (un getLong para
Time) y se lanza una Exception

31
Prepared Statements
 Donde se ha usado Satement es generalmente posible
usar PreparedStatement para hacer más eficientes las
consultas
 Una instrucción con PreparedStatement va a ser, en la
mayoría de los casos, traducida a una consulta SQL nativa
de la base de datos en tiempo de compilación
 La otra ventaja es que es posible usar parámetros dentro
de ella, pudiendo hacer más flexibles las consultas o hacer
varias consultas distintas dentro de un ciclo cambiando el
valor de algunas variables
PreparedStatement us = con.prepareSatatement(
“update alumnos set comuna = ? where direccion
like = ?”);
us.setString(1,’Santiago’)
us.setString(2,’Portugal’);

32
Prepared Statements: Ejemplo
PreparedStatement updateSales;
String updateString = "update COFFEES “+
"set SALES = ? where COF_NAME like ?";
updateSales = con.prepareStatement(updateString);
int [] salesForWeek = {175, 150, 60, 155, 90};
String [] coffees = {"Colombian", "French_Roast",
"Espresso", "Colombian_Decaf",
"French_Roast_Decaf"};
int len = coffees.length;
for(int i = 0; i < len; i++) {
updateSales.setInt(1,salesForWeek[i]);
updateSales.setString(2, coffees[i]);
updateSales.executeUpdate();
}

33
Transacciones
 Una transacción consiste en una o más
sentencias que han sido ejecutadas y
luego confirmadas (commit) o
deshechas (rolled back)
 Auto-commit está preseteado.
 Si Auto-commit está desactivado se
debe usar los métodos “commit” o
“rollback” explícitamente.

34
Transacciones
 Para hacer uso de transacciones debe
primero dessetearse elauto-commit
 con.setAutoCommit(false)
 PreparedStatement ps = .....
 ....
 ps.executeUpdate() ....
 ps.excecuteUpdate() ...
 con.commit();

35
Stored Procedures

 Es un grupo de sentencias SQL que se


agrupan lógicamente en una unidad para
efectuar una determinada tarea
 Existen en la mayoría de los DBMS pero son
dependientes de estas (no es muy estándar
la forma cómo se escriben/ejecutan)
 Generalmente reciben parámetros
 Se “escriben” con un Update y se ejecutan
con un Query

36
Un ejemplo
Para crear el Stored Procedure
String crearSP = “create prodcedure SHOW_SUPPLIERS”+
“ as ”+
“select SUPPLIERS.SUP_NAME, COFFEES.COF_NAME”+
“from SUPPLIERS, COFFEES ”+
“where SUPPLIERS.SUP_ID = COFFEES.SUP_ID”

Statement stmt = con.CreateStatement();


stmt.executeQuery(createSP);

Para llamar el Stored Procedure


CallableStatement cs;
cs = con.prepareCall(“{call SHOW_SUPPLIERS}”);
ResultSet rs = cs.executeQuery();

37
Usando los metadatos
 Los metadatos son la información acerca de la
estructura de una Base de Datos o un ResultSet
 Se obtiene con el método getMetaData()
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);

ResultSetMetaData rsmd = rs.getMetaData();

int numberOfColumns = rsmd.getColumnCount();

int rowCount = 1;

while (rs.next()) {

 System.out.println("Row " + rowCount + ": ");


 for (int i = 1; i <= numberOfColumns; i++) {
 System.out.print(" Column " + i + ": ");
 System.out.println(rs.getString(i));
 }
 System.out.println("");
 rowCount++;
}

38
Usando los metadatos
 Ejemplo para conocer las tablas de una Base de Datos

 DatabaseMetaData dbmd = con.getMetaData();


 String dbmsName = dbmd.getDatabaseProductName();
 ResultSet rs = dbmd.getTableTypes();
 System.out.print("The following types of tables are ");
 System.out.println("available in " + dbmsName + ": ");
 while (rs.next()) {
 String tableType = rs.getString("TABLE_TYPE");
 System.out.println(" " + tableType);
 }

39