sábado, 11 de agosto de 2012

Ultima Clase

Al fin y despues de tanto tiempo lo prometido los codigos de la ultima clase.

Para poder trabajar correctamente los codigos es necesario que tengamos en nuestra base de datos dos tablas, una para almacenar a personas y otra para alamacenar futbolistas. Estas entidades estan represenatdas por nuestras clases Persona y Futbolista, asi que deben de contener los atributos que queramos almacenar de las instancias de estos objetos.

La tabla persona puede definirse como:

+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| nombre    | varchar(80) | YES  |     | NULL    |       |
| peso      | float       | YES  |     | NULL    |       |
| edad      | int(11)     | YES  |     | NULL    |       |
| sexo      | tinyint(1)  | YES  |     | NULL    |       |
| idpersona | varchar(8)  | NO   | PRI |         |       |
+-----------+-------------+------+-----+---------+-------+


Y la tabla futbolista como:

+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| equipo    | varchar(50) | NO   | PRI |         |       |
| posicion  | varchar(50) | NO   | PRI |         |       |
| idpersona | varchar(8)  | NO   | PRI |         |       |
+-----------+-------------+------+-----+---------+-------+


Bien ahora ya que tenemos nuestras tablas creadas, vamos a escribir las clases que se van a encargar de ir a escribir, leer, actualizar y borrar.

Empecemos por crear la clase que se encargara de hablar con la entidad persona, se llamara PersonaPersist y la colocamos en el paquete sociedad.datos, para indicar que se trata de una clase que interactuara con la BD.

  package sociedad.datos;

  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import sociedad.Persona;

  public class PersonaPersist {
 
   public static void persist(Connection con, Persona p) throws SQLException{
    String st = "INSERT INTO persona(nombre,peso,edad,sexo,idpersona) VALUES(?,?,?,?,?)";
    PreparedStatement pst;
    
    pst = con.prepareStatement(st);
    pst.setString(1, p.getNombre());
    pst.setFloat(2, p.getPeso());
    pst.setInt(3, p.getEdad());
    pst.setBoolean(4, p.isMujer());
    pst.setString(5, p.getIdPersona());
    pst.executeUpdate();
    
   }
  }


Con el metodo persist() vamos a guardar una persona en la base de datos.

En la variable st tenemos la sentencia SQL que ejecutara el GBD(Gestor de Base de Datos) como vemos la hemos escrito usando la forma:

INSERT INTO tabla(atr1, atr2, ...) VALUES (val1, val2, ...)

para hacer esto mas ententible a todas las personas que lean nuestro codigo(esto me incluye a mi y a ti que estas leyendo) y hemos utilizado un caracter ? donde van los valores que deseamos almacenar.

Con la linea con.prepareStatement(st); le decimos al GBD que compile la sentencia SQL almacenada en el string st, con esto se logra una ejecucion mas rapida del SQL de nuestros modulos y ademas establece los valores permitidos para cada campo que vamos a guardar.

Cuando escribimos pst.setString(1, p.getNombre()); estamos indicando que el PreparedStatement va a settear un string en el parametro 1 y que vale lo que tenga el atributo nombre de la persona p. Hacemos esto tantas veces como signos ? hallamos puesto en nuestro query, utilizando el metodo set adecuado(setFolat(), setInt(), ...).

Finalmente el metodo pst.executeUpdate(); va a mandar ejecutar el query para almacenar a nuestra persona en la BD.

En este punto te pregunto

¿aun armas querys concatenando strings?

De responder NO, te felicito utilizas buenas practicas de programacion
Si me dices que SI, no te preocupes todos lo hemos hecho alguna vez nadie nace sabiendo, es malo utilizar concatenacion para armar cadenas SQL debido a que existen muchos personajes con los conocimientos suficientes de SQL Injection para tirar nuestro sistema y llevarse la informacion que almacenemos en el repositorio de datos. Haciendo uso de PreparedStaments les dificultamos esta tarea ya que estos validan que el valor que enviemos al GBD concuerde con lo que este espera recibir.

...para tu tren, ¿que es eso de throws SQLException?

Eso mis amigos quiere decir que el metodo puede fallar, si has leido bien nuestro metodo puede fallar, como todo en esta vida no podemos decir que algo se comportara de la misma manera siempre, nuestro metodo puede fallar por que no encuentre la tabla, no este disponible la base de datos, halla mucho retraso en la red, etc.

Con throws le decimos a la JVM, si llego a fallar, por favor dile a quien me mando ejecutar porque falle; sabemos que el metodo puede no terminar satisfactoriamente lanzamos el error porque a persist() unicamente le interesa escribir en la BD el no sabe que hacer con los errores, la clase que invoque el metodo sera la que se encargue de tratar el error de manera correcta.

Listo ya podemos guardar personas ahora necesitamos guardar futbolistas, sencillo creemos una clase que haga eso

  package sociedad.datos;

  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import sociedad.atleta.Futbolista;
  import sociedad.atleta.util.PosicionFutbol;

  public class FutbolistaPersist {

   public static void persist(Connection con, Futbolista f) throws SQLException{
    String st = "INSERT INTO futbolista(equipo,posicion,idpersona) VALUES(?,?,?)";
    PreparedStatement pst;
    
    pst = con.prepareStatement(st);
    for(PosicionFutbol pos : f.getPosicion()){
     pst.setString(1, f.getEquipo());
     pst.setString(2, pos.toString());
     pst.setString(3, f.getIdPersona());
     pst.executeUpdate();
    }
   }
  }


Ya esta hemos creado la clase que se va a comunicar con la BD para guardar la informacion de los futbolistas.

Ahora les presento a la nueva clase ConexionDB le he agregado metodos para utilizar transacciones en nuestras idas a la base de datos, esto para garantizar la integridad de los datos

  package sociedad.datos;

  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.SQLException;

  public class ConexionDB {
   
   public static Connection conectar(String url, String usr, String pass){
    try {
     Class.forName("com.mysql.jdbc.Driver");
     return DriverManager.getConnection("jdbc:mysql://" + url, usr, pass);
    } catch (ClassNotFoundException | SQLException e) {
     e.printStackTrace();
    }
    return null;
   }
   
   public static Connection conectar(String url, String usr, String pass, boolean autoCommit){
    Connection con = conectar(url, usr, pass);
    
    try {
     con.setAutoCommit(autoCommit);
    } catch (SQLException e) {
     e.printStackTrace();
    }
    
    return con;
   }
   
   public static void cerrarConexion(Connection cx){
    if(cx != null)
     try {
      cx.close();
     } catch (SQLException e) {
      e.printStackTrace();
     }
   }
   
   public static void rollbackTransaction(Connection cx){
    try {
     cx.rollback();
    } catch (SQLException e) {
     e.printStackTrace();
    }
   }
   
   public static void commitTransaction(Connection cx){
    try {
     cx.commit();
    } catch (SQLException e) {
     e.printStackTrace();
    }
   }
   
  }


Donde:
  • conectar(String, String, String, boolean) nos va a servir para crear una conexion a la base de datos indicandole si queremos o no que los cambios en la BD se confirmen inmediatamente despues de ejecutar una sentencia, atraves del parametro boolean.
  • rollbackTransaction() va a ayudar a cancelar la transaccion que acabemos de ejecutar en caso de que algo halla salido mal.
  • commitTransaction() sera el encargado de confirmar la transaccion cuando todo se ejecute OK.

Tenemos las clases que nos van a ayudar con la BD, ahora solo nos falta la clase que las va a invocar y sabe que hacer en caso de que ocurra un error, en este ejemplo he propuesto la clase RegSocl.

  package sociedad.proceso;

  import java.sql.Connection;
  import java.sql.SQLException;
  import sociedad.Persona;
  import sociedad.atleta.Futbolista;
  import sociedad.datos.ConexionDB;
  import sociedad.datos.FutbolistaPersist;
  import sociedad.datos.PersonaPersist;

  public class RegSocl {
   public static void guardaPersona(Persona persona){
    Connection con;
    
    con = ConexionDB.conectar("127.0.0.1/sociedad?useServerPrepStmts=true", "root", "");
    try {
     PersonaPersist.persist(con,persona);
    } catch (SQLException e) {
     e.printStackTrace();
    }finally{
     ConexionDB.cerrarConexion(con);
    }
   }
   
   public static void guardaFutbolista(Futbolista futbolista){
    Connection con;
    
    if(futbolista.getPosicion() != null){
     con = ConexionDB.conectar("127.0.0.1/sociedad?useServerPrepStmts=true", "root", "", false);
     
     try {
      PersonaPersist.persist(con, futbolista);
      FutbolistaPersist.persist(con, futbolista);
     } catch (SQLException e) {
      ConexionDB.rollbackTransaction(con);
      e.printStackTrace();
      System.out.println("No se pudo guardar en BD");
     }
     ConexionDB.commitTransaction(con);
    }
   }
  }


Con guardaPersona() invocamos nuestro metodo PersonaPersist.persist() dentro de un bloque try...catch debido a que como bien dijimos antes nuestro codigo puede fallar, haciendo esto podemos atrapar la excepcion y tratarla de la mejor manera posible, para este ejemplo unicamente imprimimos el error.

La sintaxis completa del bloque try...catch es:

  try{
   ...
   codigo que puede fallar
   ...
  }catch(Exception e){
   ...
   codigo en caso de que haya ocurrido un error
   ...
  }finally{
   ...
   codigo que siempre debe ejecutarse con o sin errores
   ...
  }


El metodo guardaFutbolista() llamara a nuestro metodo para guardar personas(para almacenar su informacion de persona) y posteriormente el de futbolistas(para guardar su informacion de futbolista), en caso de que un error ocurriera hace rollback a la transaccion descartando los cambios si todo sale bien hace commit y se guarda la informacion de nuestro futbolista.

A probar nuestro codigo, creemos una clase main con el codigo necesario para guardar personas y futbolistas en nuestra BD, pero esa labor es para usted estimado lector.

Les dejo el codigo completo aqui para que lo revisen incluye lo poquito que vimos de swing tambien para los que comentaron acerca de conceptos basicos en Java les dejo este libro y este otro es de cajon.

Espero el curso halla sido de su agrado
No olviden comentar
¡¡Saludos a todos!!
Nos leemos en la siguiente entrada