Download Java7-JDBC - DCC - Universidad de Chile

Document related concepts
no text concepts found
Transcript
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

Cliente
Aplicación
Java
JDBC
Protocolo
BD
DBMS
Servidor BD
5
De 2 capas
 La aplicación “habla” directamente con
la base de datos.
 Controlador JDBC se comunica con el
sistema específico que maneja la base
de datos.
 La base de datos puede estar en otra
máquina, con lo que el cliente se
comunica por red. Esta es la
configuración llamada cliente/servidor.
Modelos de acceso a BD
De 3 capas
 Los comandos son enviados a la
Navegador
Web
capa intermedia de servicios, la
cual envía sentencias SQL a la
Protocolo HTTP
base de datos. Ésta las procesa
Aplicación
Servlets, JSP y envía los resultados de vuelta
a la capa intermedia, para luego
en servidor
Java
WEB
ser enviados al cliente.
JDBC
 Permite un control de acceso y
Protocolo BD
de actualización.
 Provee ventajas de
Servidor
performance.
DBMS
Cliente (GUI)
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);


8
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.
Conexión

Ejemplos de URL:




9
jdbc:mysql://localhost/test (para ejemplos)
jdbc:oracle://oraserver
jdbc:odbc:mydatabase
jdbc:ldap://server;baseDN=baseDN;useCle
artext=true
...Conexión

Sintáxis de una URL JDBC:



10
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
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:



13
“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.
La clase Statement



14
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
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=’[email protected]’”
+“where id=’123’”
);
s.executeUpdate(
“update from prestamos set fecha=’20060913’”
+“where idLibro=’JA1’”
);
Retorno de excuteUpdate
•
•
•
•
19
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>
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
ref
objeto
r
fila
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:



30
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
La instrucción getXXX



31
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
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



34
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.
Transacciones

Para hacer uso de transacciones debe
primero dessetearse elauto-commit






35
con.setAutoCommit(false)
PreparedStatement ps = .....
....
ps.executeUpdate() ....
ps.excecuteUpdate() ...
con.commit();
Stored Procedures




36
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
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