Mostrando entradas con la etiqueta JDBC. Mostrar todas las entradas
Mostrando entradas con la etiqueta JDBC. Mostrar todas las entradas

jueves, 26 de julio de 2007

Recursos sobre JDBC

Algunos enlaces interesantes sobre JDBC:

  1. Curso de JDBC oficial.
  2. Curso de lo mismo pero en Español.
  3. JDBC en el JavaTutorial.

Acceso y abstracción de datos

El acceso a la base de datos suele ser un poco complicado y repetitivo, para manejar las cuestiones generales de datos podemos utilizar algunos patrones de diseño para generar clases que puedan encargarse de conectarse a las bases de datos y actualizar estas de la manera más abstracta posible, el primer paso para esto es la conexión de datos compartida.

Dado que en Java no existen variables globales, es necesario buscar otra aproximación para compartir la conexión a lo largo de toda la aplicación, el modelo Singleton puede ayudarnos en esto, en este modelo existe una clase de la que solamente puede existir un elemento en un determinado momento. Un singleton sencillo podría verse más o menos de la siguiente forma.


public class ConexionDB {
private static ConexionDB instance = null;
private Map conexiones;

//El acceso privado hace imposible instanciar directamente esta clase
private ConexionDB() {
conexiones = new LinkedHashMap();
}

//Si requerimos una instancia de la clase deberiamos llamar a este metodo
private static ConexionDB getInstance() {
//LazyInstancing. Creamos el objeto hasta que se necesita
if(instance == null)
instance = new ConexionDB();
return instance;
}

public Connection getIConnection(String driver, String uri, String user, String pass) {
try {
//Verificamos si la conexión no existe ya en Cache
if(conexiones.hasKey(uri))
return (Connection) conexiones.get(uri);

Class.forName(driver);
Connection c = DriverManager.getConnection(uri, user, pass);
conexiones.put(uri, c);

return c;
} catch(Exception e) {
return null;
}
}

//Simplificamos las llamadas para no depender del Singleton en código general
public static Connection getConnection(String driver, String uri, String u, Stirng p) {
return ConexionDB.getInstance().getIConnection(driver, uri, u, p);
}

//Generalmente siempre se usa una sola conexión a DB por default
public static Connection getDefaultConnection() {
return ConexionDB.getInstance().getIConnection("sun.jdbc.odbc.JdbcOdbcDriver",
"jdbc:odbc:osos", "sa", "admin");
}
}


Para utilizar la conexión en otra clase solamente utilizariamos código sencillo:


Connection c = ConexionDB.getConnection("driver", "uri", "user", "pass");
Connection c2 = ConexionDB.getDefaultConnection();

domingo, 22 de julio de 2007

JDBC Parte 2

Quedamos entonces por empezar con el manejo de consultas con parametros. Normalmente para esto y en la práctica no se utiliza la clase Statement sino la clase PreparedStatement. Vamos a ver como funciona para cosas simples.


PreparedStatement ps = c.prepareStatement("SELECT * FROM tabla");
ResultSet rs = ps.executeQuery();
//Podemos usar ps.executeUpdate();
//para DDL o SQL de actualización y este devuelve un entero con lo que paso


Lo divertido de un PS no es realmente esto, sino las consultas parametrizadas.


try {
PreparedStatement ps = c.prepareStatement("SELECT * FROM tabla WHERE id=?");
ps.setInt(1, 9);
//Igualmente puede utilizarse setString, etc
ResultSet rs = ps.executeQuery();
} catch(Exception e) {
System.out.println("Error en la consulta");
}


Las consultas parametrizadas deberían utilizarse siempre que se actualizan datos a una base de datos para evitar SQLInjection y otros problemas como carácteres extraños y cosas por el estilo.

La clase CallableStatement nos permite tener acceso a procedimientos almacenados en la base de datos que se hayan definido anteriormente. Por ejemplo:


try {
CallableStatement cs = c.prepareCall("{call getDailyTotal (?, ?)}");
cs.setInt(1, 7);
cs.getString(2, "Hola");
} catch(Exception e) {
System.out.println("Error de DB");
}


Sin mayores detalles así funciona. Vamos ahora a terminar con JDBC hablando de las transacciones. Estas se utilizan para crear acciones atómicas sobre la base de datos.


try {
c.setAutoCommit(false);
c.prepareStatement("SQL 1").executeUpdate();
c.prepareStatement("SQL 2").executeUpdate();
c.prepareStatement("SQL 3").executeUpdate();

c.commit();
} catch(Exception e) {
try {
c.rollback();
} catch (Exception exc) { ; }
System.out.println("Error de DB");
}

sábado, 21 de julio de 2007

Conexiones JDBC

La tecnología parte de Java que se encarga de realizar conexiones a bases de datos se conoce como JDBC (Java Data Base Conection); es un estandar que define las reglas que deben seguir cada uno de los proveedores para poder hacer que sus datos sean accesibles en programas Java.

La idea detras de esto es que un constructor de DB crea un programa de base de datos, y una vez creado este se crea entonces una aplicación java conocida como Driver que se encarga de dar los datos a Java de una manera previamente definida.

Los Dirvers de base de datos vienen en varios estilos pero todos funcionan de manera similar en su superficie.

Para establecer una conexión a BD desde Java se necesita:

  1. La clase Driver que se encargara de gestionar la conexión.
  2. Una URL especial para acceder a la base de datos.
  3. Un consumidor de datos (el programa Java mismo).
El código general para establecer una conexión se muestra a continuación, el ejemplo considera un servidor SQL Server con una base de datos llamada osos accesible a traves de un ODBC con la misma dirección.


try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
} catch (ClassNotFoundException) {
System.out.println("El Driver no existe");
}

Connection c = null;
try {
// c = DriverManager.getConnection("jdbc:odbc:osos", "usuario", "password");
// en caso de que el ODBC no incluya estos datos.
c = DriverManager.getConnection("jdbc:odbc:osos");
} catch (Exception e) {
System.out.println("No se puede establecer una conexión");
}


La forma de crear la URL que se pasa a getConnection y la clase que se pasa a forName dependen del tipo de base de datos al que se desee conectar, en general usar ODBC es una buena idea, pero la clase que utiliza Java para gestionar el ODBC es muy poco practica, por lo que deberia sustituirse por un Driver especifico. Puede encontrarse en la página de Java una lista de drivers existentes.

Una vez que se dispone del código que genero el objeto Connection se empieza a interactuar con el de una manera común. Se puede utilizar un objeto de esta naturaleza por medio de sentencias o directamente y con o sin transcciones. Primero vamos a revisar como realizar una consulta a la base de datos para obtener datos. Para esto vamos a utilizar la clase Statement, esta clase almacena la mayoría de la funcionalidad de interacción con SQL.


Statement st = c.createStatement();

try {
st.execute("CREATE TABLE");
st.execute("DELETE FROM tabla WHERE id=" + id);
st.execute("INSERT INTO tabla VALUES('id')");
st.execute("ANY_VALID_SQL_FOR_DB");
} catch(Exception e) {
System.out.println("El SQL charcho");
}


Con esta estrategia puedes ejecutar casi todo el SQL que no regrese datos. Ahora, con datos: se necesita ahora la clase ResultSet, que representa un conjunto de datos que se encuentran almacenados en la base de datos. Vamos entonces a lo nuestro.


try {
ResultSet rs = st.executeQuery("SELECT * FROM M");
//mira, primero hay que moverlo
rs.first();
//podemos usar rs.next(), el resto (rs.previous() y rs.last() causan a veces conflictos)

String s = rs.getString("nombre_campo");
String s2 = rs.getString(1); //El primer campo
int pos_campo = rs.findColumn("campo"); //Devuelve la posicion del campo

int r = rs.getInt(2); //Igual existen getDouble(), getLong(), getObject(), entre otros
} catch(Exception e) {
System.out.println("El SQL charcho");
}


Weno, después completo el tema del SQL, quedan pendientes los procedimientos almacenados, la manera realmente practica de hacer las cosas, porque esta es algo viejita y las transacciones. Empiezen a jugar con esto, como ejercicio creen una aplicación Java que cree toda la estructura de una base de datos de una bilbioteca y le inserte algunos datos.