Marcar registros modificados en MySQL

Trigger
Trigger

Supongamos el siguiente problema, tiene una tabla MySQL que va a ser modificada, a la brava por un programa tercero y cada vez que se modifique esa tabla debe usar esos valores para recalcular un total en otro lado, ¿Como le hace?

Si bien lo obvio es tener algún programa que revise esa tabla en forma regular queda el problema de como saber cual registro se modificó, bueno hay una solución que aprovecha una característica de MySQL, los disparadores o triggers.

Triggers

Estos son funciones que se llaman automáticamente al insertar, actualizar o borrar un registro de una tabla y nos permiten efectuar comparaciones y modificar los valores justo antes o después de que ocurra uno de los eventos mencionados, como se ven el la figura con los seis triggers disponibles: before insert, after insert ,before update, after update, before delete y after delete.

Para nuestro caso de marcar un registro modificado usaremos el trigger before update.

Trigger Before Update

Este es el trigger en particular que usaremos para detectar y marcar modificaciones en la tabla, se activa justo antes de aplicar los cambios en base de datos, al momento en el que ambos, el registro actualizado y el registro anterior, están en la memoria de modo que podemos acceder a los valores de ambos, usando NEW y OLD para representar los registros antes y después de la actualización, para efectuar comparaciones.

Ejemplo

Como un ejemplo para dejar las cosas en claro crearemos un trigger que cambie el campo modificado de cero a uno cada vez que se modifique ese registro y que nos deje cambiar el campo modificado a cero otra vez.

Sobra decir que la tabla donde quiera aplicar este trigger debe tener un campo que se llame modificado y que acepte 0 y 1 como valores, si no lo tiene modifique una tabla que tenga para hacer el experimento.

Para crear el trigger usaremos el siguiente comando:

CREATE DEFINER=`root`@`localhost` TRIGGER `test`.`folios_test_BEFORE_UPDATE` BEFORE UPDATE ON `folios_test` FOR EACH ROW
BEGIN
if old.modificado = 0 then
set new.modificado = 1;
end if;
END

Puede hacerlo directamente desde las consultas de MySQL Workbench o desde las propiedades de la tabla en la pestaña Triggers como se ve en la figura al inicio.

Lo que estamos haciendo aquí es lo siguiente:

  1. Antes de aplicar la actualización vemos si el campo modificado del registro previo a la actualización (OLD) esta en cero, si lo esta procedemos al paso 2 sino se deja como esta, esto es necesario para poder regresar el registro de uno a cero.
  2. Cambiamos el valor de modificado a 1 en el registro actualizado (NEW)
  3. Se actualiza el registro con los valores de NEW, esto lo hace automáticamente la base de datos, pero lo pongo para que sepa por que cambiamos el valor de modificado usando NEW

Ya que aplique el trigger, sea corriendo el comando o desde las propiedades de la tabla, abra la tabla donde aplicó el trigger y modifique un registro.

Tabla antes de modificar
Tabla antes de modificar
Tabla despues de modificar
Tabla despues de modificar

Notara que el valor de modificado cambio de 0 a 1, ahora mueva el valor de modificado de vuelta a 0.

Modificado en cero
Modificado en cero

Notara que aunque modificamos el registro el valor de modificado no paso a 1 automáticamente, esto se debe al if que pusimos en el trigger que solo permite cambiar el valor de modificado si este esta en cero.

No hay un limite a la cantidad de instrucciones que puede poner dentro de un trigger y tampoco se limitan a esa misma tabla, por lo que podría usar un trigger para modificar otra tabla al instante sin problemas, nada mas recuerde no excederse o podría volver muy lentas las operaciones donde se corra el trigger.


Espero que esta entrada fuera de utilidad y si lo fue y quiere cooperar con la causa tengo una pagina en Ko-fi para aceptar donativos

ko-fi

Anuncios

Iniciando MySQL manualmente en Windows

¿¡DONDE ESTA MYSQL!?
¿¡DONDE ESTA MYSQL!?

No me diga, tenia su servidor MySQL corriendo en una flamante máquina con Windows 10 y no solo le cayó una actualización que forzó el reinicio de la computadora (pese a que tenia desactivadas las actualizaciones automáticas) y ahora el proceso MySQL no funciona, el administrador de tareas no muestra el proceso mysqld y peor aun el servicio MySQL ya no aparece en la lista de servicios del sistema.

Antes que se desespere, le prenda velas a San Isidoro de Sevilla y reinstale la máquina rezando que pueda rescatar la base de datos directo del disco y con el mal presentimiento que esto puede volver a pasar hay algo que debo decirle.

Sabias palabras si alguna vez las hubo
Sabias palabras si alguna vez las hubo

Si bien es poco probable que pueda volver a crear el servicio MySQL (si sabe como digame por que yo gaste casi una semana tratando de hacer eso) y en efecto esa actualización caerá de nuevo haga lo que haga le puedo decir como arrancar el servicio MySQL de nuevo en una forma muy sencilla.

Para esto necesita hallar un par de rutas en su sistema, la ubicación del ejecutable mysqld y el archivo .ini de configuración.

Aqui esta mysqld
Aqui esta mysqld

Mysqld usualmente estará en

C:\Archivos de programa\MySQL\MySQL Server 5.5\bin\mysqld.exe

Obviamente la ruta cambiara según el idioma de su sistema y la versión de MySQL instalada, pero esa ruta le servirá para empezar a buscar.

Aqui esta el my.ini
Aqui esta el my.ini

Ahora necesita el archivo de configuración my.ini, este por defecto lo encontrará en

C:\ProgramData\MySQL\MySQL Server 5.5\my.ini

Como con mysqld la ubicación de este archivo puede cambiar dependiendo de la versión de MySQL y de su sistema pero esa es la ubicación por defecto, también recuerde que C:\ProgramData es un directorio que normalmente se encuentra oculto por lo que si no lo ve ponga haga visibles los directorios ocultos primero.

Ya que tenga esas dos rutas anotadas cree el siguiente comando:

“” –defaults-file=””

Que basado en el sistema donde me paso quedaría asi

"C:\Program Files\MySQL\MySQL Server 5.5\bin\mysqld" --defaults-file="C:\ProgramData\MySQL\MySQL Server 5.5\my.ini"

Este comando le permitirá iniciar el servidor MySQL indicándole a este cual archivo de configuración desea usar.

Ya que lo tenga abra el Administrador de tareas y vaya a la opción “Crear nueva tarea”, copie el comando que creo al campo Abrir e indique que desea crear esa tarea con privilegios administrativos.

Ejecutamos el comando.
Ejecutamos el comando.

¡Y listo!, tras eso volverá a ver corriendo el proceso mysqld y la base de datos volverá a estar disponible y las aplicaciones que dependían de esta volverán a funcionar.

La gran desventaja de iniciar así el MySQL es que si reinicia la máquina deberá de volver a correr el comando, por el momento no conozco una solución confiable para remediar eso.

Como una recomendación adicional antes de correr el comando confirme que no halla otro proceso mysqld corriendo, esto puede pasar si intento forzar el servicio a arrancar, en ese caso esta corriendo, pero con los datos de instalación no con su base de datos, por lo que debe de terminarlo antes correr el comando.

Espero que la información aquí le fuera útil y nos vemos en la próxima entrada.

De las virtudes de la pereza

Pereza
Pereza

Bien dijo Bill Gates “Siempre elijó a una persona perezosa para hacer el trabajo difícil, por que probablemente encontrará la forma mas fácil para llevarlo a cabo” y si bien implicó aprender como funcionan las anotaciones, la reflexión y genéricos de Java creo ya me libre de una de las partes mas tediosas de leer una base de datos MySQL en Java ya esa esa donde tiene que andar..

objecto.setCantidad(data.getInt("cantidad"));
objecto.setCantidad(data.getDouble("iva"));
objecto.setCantidad(data.getDouble("precio"));
objecto.setCantidad(data.getDouble("ganancia"));
objecto.setCantidad(data.getDouble("ieps"));
objecto.setCantidad(data.getString("codigo"));
objecto.setCantidad(data.getInt("ventas"));
objecto.setCantidad(data.getDouble("ganancia"));
objecto.setCantidad(data.getDouble("iva22"));
objecto.setCantidad(data.getDouble("iva12"));
objecto.setCantidad(data.getDouble("iva21"));
objecto.setCantidad(data.getInt("nuevo_version"));
objecto.setCantidad(data.getString("clave"));
objecto.setCantidad(data.getString("ruta1"));
objecto.setCantidad(data.getString("ruta10"));
objecto.setCantidad(data.getInt("activo"));

Que es simple y practico hasta que tiene una tabla con 50 campos *todos* necesarios en el programa..

Con suerte aplicando las tres características del Java ya mencionadas este paso se puede simplificar y básicamente hacer en automático, el como se hace lo pondré después (ya que termine unas pruebas mas y vea si puedo hacer esas explicaciones en formato de comic), pero mientras deje pongo en forma resumida algunos de los hallazgos.

  • Crear anotaciones en Java es mucho mas sencillo de lo que parece, aunque hay que tener cuidado con @Retencion y @Target.
  • En tiempo de ejecución puede saber los miembros de una clase, las anotaciones tanto de la clase como de los miembros y mas importante la información contenida.
  • Los genéricos en Java tampoco son ciencia de cohetes, unas cosas requieren hacerse de una forma diferente a la usual, pero no es nada del otro mundo y es mejor que estar haciendo conversiones de clases a cada rato.
  • Eso de la reflexión puede entrar en conflicto con los getter y setter, mas que nada por que los miembros suelen ser privados y llamar a los getter/setter con una cadena de texto esta a una letra mayúscula incorrecta de un error muy feo, pero para eso esta Apache BeanUtils que se encarga de eso.
  • Usar Object como clase intermedia (o puntero generico) parece ser menos peligroso de lo que pensaba
  • Aunque la notación de Genericos en Java suele ser < E >lo que va entre los < > puede ser cualquier cosa, como por ejemplo < claseGenerica > o algo mas legible.

Haciendo esto puede automatizar la consulta y pasar la información a un objeto Java y muy posiblemente automatizar la creación de los comandos update e insert de MySQL.

Tal vez se pregunte por que no usar un framework que ya haga eso como podría ser Hibernate y si bien es una posibilidad es un poco pesado para lo que necesito y tarda mucho en iniciar.

Ya veremos como hacer todo esto próximamente, por lo pronto espero que algo de aquí le fuera de utilidad y nos vemos en la próxima :).

 

Pooling de Conexiones a base de datos con C3P0 y Java

Un pool de conexiones a base de datos es una forma de llevar un control de las mismas de modo que al desocupar una conexión, en lugar de cerrar la conexión la tengamos a la mano y se entregue al siguiente objeto que necesite una conexión.

Si bien esto puede sonar innecesario debe de recordar que crear una conexión a base de datos es una de las operaciones mas pesadas que puede efectuar y que las conexiones expiran automáticamente después de un tiempo sin uso, ambas cosas que pueden afectar el rendimiento o estabilidad de su aplicación.

Ahí es donde entra el pool de conexiones ya que este se encargara de reducir el numero de veces que necesite crear una nueva conexión y en caso que esta expire crea una nueva si es necesario.

Pool de conexiones C3P0

Uno de los pools de conexiones mas populares actualmente es el C3P0 proporcionado por Machinery For Change, Inc, este le proporciona todas las funcionalidades esperadas a la vez que se integra con gran facilidad a otros frameworks de Java.

Debido a su popularidad y sencillez de uso nos enfocaremos en como hacer uso de este pool en particular.

Obtener las librerías de c3P0.

Vaya a la pagina oficial del proyecto: http://www.mchange.com/projects/c3p0/ o directamente al repositorio en SourceForge y descargue la versión mas reciente.

En el archivo .zip que descargo vaya a la carpeta lib y extraiga los archivos c3p0-0.9.5.2.jar, c3p0-oracle-thin-extras-0.9.5.2.jar y mchange-commons-java-0.2.11.jar con estos ya podrá usar el pool en su proyecto.

A su vez necesitara de la librería para usar conexiones a base de datos, agregue esta a su proyecto como se ve en la figura 2.

2016-04-18
Figura 1 – Librerías de C3P0.
2016-04-18 (1)
Figura 2 – Librerías del proyecto.

Estos archivos .jar pueden agregarse a un proyecto como ya lo hemos hecho con anterioridad.

Uso del pool C3P0 en un programa.

En el ejemplo que se utilizara para demostrar el uso del pool seguramente notará un par de cosas un tanto inusuales, específicamente que obtendremos el pool de conexiones vía un método getInstance en lugar de un constructor, obtendremos las conexiones desde el pool  y que haremos un uso constante del método close del objeto conexión.

El uso del getInstance es por una razón muy sencilla, haciendo el pool un objeto estático y obteniendo este vía el getInstance podemos tener el *mismo* pool disponible en todo el programa sin necesidad de estar pasando ese objeto a cada una de las clases, se los digo por experiencia, tener que agregar un parámetro extra a cada constructor y crear los getter y setter necesarios se vuelve aburrido de inmediato.

El obtener las conexiones desde el pool es necesario para poder obtener los beneficios de este, fuera de eso se comportan de manera usual por lo que no necesita modificar cómo realiza sus consultas.

Con respecto a llamar el método close esto es necesario para indicar al pool que ya no estamos usando esa conexión, de modo que esté disponible para cuando se solicite, es *vital* que recuerde llamar al método close o que use la estructura try-with-resources proporcionada por Java, ya que el no hacer esto puede trabar su aplicación, ese caso se verá en el ejemplo.

Ejemplo.

El ejemplo que se presentará es muy sencillo, pero presenta los detalles de como crear la clase para manejar el pool  y cómo usar esta en un programa de una forma que, espero, sea lo más legible y sencilla de entender posible.

El ejemplo consistirá en dos clases, una que crea y configura el pool y otra desde la cual realizaremos una serie de consultas a la tabla de base de datos que se ve en la figura 3.

2016-04-20 (2)
Figura 3 – Tabla a presentar.
package c3p0ejemplo;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Connection;

public class PoolC3P0 {
 // Notara que el pool es un miembro *estatico* esto es para evitar duplicidad
 private static PoolC3P0 datasource;
 // Esta es la fuente de datos que conecta con la base de datos
 private final ComboPooledDataSource cpds;

 /**
  * Crea el constructor del pool, notara que este constructor es privado
  * esto con el fin de que podamos controlar cuando se crea el pool
  * @throws IOException
  * @throws SQLException
  * @throws PropertyVetoException
  */
 private PoolC3P0() throws IOException, SQLException, PropertyVetoException {
  // Configuramos la conexion a base de datos
  // Creamos la fuente de datos
  cpds = new ComboPooledDataSource();
  // Que driver de base de datos usaremos
  cpds.setDriverClass("com.mysql.jdbc.Driver");
  // La url de la base de datos a la que nos conectaremos
  cpds.setJdbcUrl("jdbc:mysql://127.0.0.1/");
  // Usuario de esa base de datos
  cpds.setUser("usuario");
  // Contraseña de la base de datos
  cpds.setPassword("contrasena");

  // Configuramos el pool
  // Numero de conexiones con las que iniciara el pool
  cpds.setInitialPoolSize(0);
  // Minimo de conexiones que tendra el pool
  cpds.setMinPoolSize(0);
  // Numero de conexiones a crear cada incremento
  cpds.setAcquireIncrement(1);
  // Maximo numero de conexiones
  cpds.setMaxPoolSize(5);
  // Maximo de consultas
  cpds.setMaxStatements(180);
  // Maximo numero de reintentos para conectar a base de datos
  cpds.setAcquireRetryAttempts(2);
  // Que se genere una excepcion si no se puede conectar
  cpds.setBreakAfterAcquireFailure(true);
 }

 /**
  * Nos regresa la instancia actual del pool, en caso que no halla una instancia
  * crea una nueva y la regresa
  * @return
  * @throws IOException
  * @throws SQLException
  * @throws PropertyVetoException
  */
 public static PoolC3P0 getInstance() throws IOException, SQLException, PropertyVetoException {

  if (datasource == null) {
   datasource = new PoolC3P0();
   return datasource;
  } else {
   return datasource;
  }
 }

 /**
  * Este metodo nos regresa una conexion a base de datos, esta la podemos
  * usar como una conexion usual
  * @return Conexion a base de datos
  * @throws SQLException
  */
 public Connection getConnection() throws SQLException {
  return this.cpds.getConnection();
 }

}
package c3p0ejemplo;

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class C3P0Ejemplo {

 /**
  * @param args the command line arguments
  */
 public static void main(String[] args) {
  try {
   // Obtenemos el pool de conexiones
   PoolC3P0 pool = PoolC3P0.getInstance();

   for (int i = 0; i < 10; i++) {
    // Solicitamos una conexion al pool
    Connection cx = pool.getConnection();
    // Creamos nuestro objecto de consulta
    Statement consulta = cx.createStatement();
    // La consulta que ejecutaremos
    String sql = "SELECT * FROM pruebas.prueba";
    // Obtenemos los datos
    ResultSet data = consulta.executeQuery(sql);
    data.next();

    Integer puerto = data.getInt("puerto_serial");
    Integer impresora = data.getInt("puerto_impresora");
    Integer red = data.getInt("puerto_red");
    Integer scaner = data.getInt("puerto_escaner");

    // Los presentamos en pantalla
    System.out.println("Vuelta numero " + i);
    System.out.println("Puerto " + puerto);
    System.out.println("Impresora " + impresora);
    System.out.println("Red " + red);
    System.out.println("Escaner " + scaner);
    System.out.println("");
    System.out.println("");

    // Cerramos la conexion, esto es vital, de no hacerlo el pool creara una nueva conexion
    // pero al cerrar liberamos esa conexion para que el pool la reuse
    cx.close();

    // Un retrazo de 10 segundos para poder ver las conexiones en MySQL Workbench
    Thread.sleep(5000);
   }

  } catch (IOException ex) {
   System.out.println("Error de entrada salida");
  } catch (SQLException ex) {
   System.out.println("Error de conexion a base de datos");
  } catch (PropertyVetoException ex) {
   System.out.println("Error de propiedades");
  } catch (InterruptedException ex) {
   System.out.println("Error de interrupcion de proceso");
  }

 }

}

Ya que ejecute el programa vera que el programa abre una conexión, consulta, presenta los datos, realiza una espera y cierra la conexión, el resultado se vera como la figura 4.

2016-04-20 (1)
Figura 4 – Salida del programa

Como ve el ejemplo pide y cierra conexiones a cada vuelta, mientras el programa se ejecuta acceda a la administración de conexiones de usuario en workbench, notara que la conexión que usamos (identificada por el usuario “usuario”) nunca cambia, no importa cuantas conexiones abramos o cerremos solo se esta usando una como vemos en la figura 5.

2016-04-20 (3)
Figura 5 – Conexiones del usuario

Como un extra modifique la tabla mientras corre el programa y vera que los datos presentados cambian en forma acorde.

Espero que la entrada fuera útil y nos vemos en la próxima.

Obtener los nombres de las columnas de una tabla MySQL con Java

mejor_modo
No mas 50 lineas de .getString(“nombre_columna”)

La forma mas común de manejar una base de datos MySQL en Java es usar los objectos Statement y ResultSet para enviar comandos a la misma y obtener el resultado de la consulta, si lo hay. En lo general este metodo funciona muy bien y le da pleno acceso a todas las funcionalidades del MySQL, ya que cada comando que use en MySQL Workbench va a funcionar sin problemas.

El unico inconveniente en este método es precisamente crear los comandos a enviar, pues sera muy comun que tenga que estar concatenando una cantidad muy grande de cadenas de texto y variables con los datos, en especial para los comandos INSERT INTO y UPDATE y si a eso le suma tablas con una enorme cantidad de datos no ha de extrañarle funciones de mas de 50 lineas en las que al menos 30 son solo repeticiones de sql = sql + “campo='” + dato + “‘, “; una y otra y otra vez, por fortuna hay una forma de automatizar la creación de ese comando y la consulta de datos.

SHOW COLUMNS FROM

El comando SHOW COLUMNS FROM <tabla> de MySQL le presenta la información sobre las columnas de la tabla, incluido el nombre de las columnas y como esta es una consulta normal de MySQL podemos ejecutarla desde Java y obtener el resultado.

Ahora, si ya tenemos los nombres de las columnas, en una forma en la que podemos iterar con un ciclo, no deberia ser dificil crear automaticamente la consulta, ¿verdad?, para nada el ejemplo a continuación presentara como hacer esto, con comentarios para detallar que ocurre.

package nombrecampos;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;

public class NombreCampos {   

  public static void main(String[] args) {
    try {
      Connection conexion;
      Statement consulta;            
      ResultSet data;
      ArrayList nombreCampos = new ArrayList<>();
      HashMap<String, Integer> datos = new HashMap<>();
            
      String user = "tecnico";
      String pass = "acceso1987";
            
      // Conectamos con la base de datos

      Class.forName("com.mysql.jdbc.Driver");

      conexion=DriverManager.getConnection(
        "jdbc:mysql://127.0.0.1:3306/pruebas"+"?"
        +"user=" + user + "&" + "password=" + pass + "");
        
      // Obtenemos los nombres de los campos de 
      //la tabla pruebas.prueba

  
      String comandoCampos = "SHOW COLUMNS FROM pruebas.prueba";
      consulta = conexion.createStatement();
      data = consulta.executeQuery(comandoCampos);
            
      while(data.next() == true) {
          
        // El campo Field es el que contiene el nombre 
        // de la columna
        
        System.out.println("Obtenemos el campo " 
        + data.getString("Field"));
          
        nombreCampos.add(  data.getString("Field") );
       }
       consulta.close();
         
       // Como prueba de que podemos usar esos nombres para
       // crear los comandos MySQL obtendremos los datos y 
       // los almacenamos el el HashMap
            
       consulta = conexion.createStatement();
       String comandoDatos = "SELECT * FROM pruebas.prueba;";
       data = consulta.executeQuery(comandoDatos);
            
        while(data.next() == true ) {
          for(String campo : nombreCampos ){
            datos.put( campo , data.getInt(campo));
            }
          }
            
          // Vemos que los datos se obtuvieran bien
          
          System.out.println("Valor de puerto_red " 
                              + datos.get("puerto_red"));

          System.out.println("Valor de isla " 
                              + datos.get("isla"));
            
          consulta.close();
            
          // Ahora cambiaremos unos valores y crearemos el 
          // comando para actualizar
          // la informacion en la base de datos
            
          datos.put("puerto_serial", 10);
          datos.put("puerto_impresora", 9);
          datos.put("puerto_red", 8);
          datos.put("red_enabled", 0);
            
          // Creamos el comando de actualizacion
          
          String comandoActualizacion="UPDATE pruebas.prueba " 
                                      + "SET ";
            
          // Usaremos un ciclo para agregar todos 
          // los campos y sus nuevos valoes
          int i;
          for(i=0; i < nombreCampos.size()-1; i++) {
            String campo = nombreCampos.get(i);            
            comandoActualizacion = comandoActualizacion 
              + campo + "=" + datos.get(campo) + ", ";
          }
            
          // El ultimo campo lo ponemos fuera del ciclo para
          // NO dejar una coma al final, o MySQL regresara error
          String campo = nombreCampos.get(i);
          comandoActualizacion = comandoActualizacion 
              + campo + "=" + datos.get(campo);
            
          // Mostramos el comando y lo ejecutamos
          System.out.println(comandoActualizacion);
          consulta = conexion.createStatement();

          consulta.executeUpdate(comandoActualizacion);            
        
      } catch (ClassNotFoundException ex) {
         System.err.println("Error de driver");
         ex.printStackTrace();
      } catch (SQLException ex) {
         System.err.println("Error de acceso a base de datos");
         ex.printStackTrace();
      }
  }    
}

Las anotaciones de los comentarios (espero) dejen en claro lo que esta ocurriendo en el codigo, lo que aqui hacemos es basicamente lo siguiente:

  1. Nos conectamos a la base de datos
  2. Obtenemos los nombres de las columnas de esa tabla
  3. Las almacenamos en un ArrayList que podamos iterar despues
  4. Usando ese ArrayList sacamos los datos de la tabla con .getInteger, sin tener que escribir los nombres de los campos uno por uno y los guardamos en un HashMap
  5. Mostramos y modificamos ese HashMap
  6. Con ayuda del arrayList creamos el comando UPDATE, de nuevo no tenemos que escribir los nombre de los campos
  7. Actualizamos la base de datos.

Como muestra a continuación estan unas capturas de la base de datos antes de correr el programa, la salida del programa y la base de datos despues de correr el programa.

01_antes
Figura 1 – Base de datos antes de correr el programa
02_salida
Figura 2 – Salida del programa
03_final
Figura 3 – Base de datos despues de correr el programa

Ahora si bien es cierto que puede actualizar la base de datos solo basandose en la posición de la columna, ese metodo me parece muy inseguro, ya que se modifica la tabla podria causar errores, este metodo, al basarse en los nombres de columna, no se vera afectado si agrega un campo nuevo al inicio.

Consultando estado de los eventos en MySQL

Al momento de crear un evento en una base de datos MySQL podría quedarle en la cabeza la duda “¿Y si se estará ejecutando?”, después de todo el MySQL no tiene un equivalente al println o un log que le permita revisar eso, por fortuna si cuenta con una tabla donde el estado de los eventos, esta tabla es INFORMATION_SCHEMA.EVENTS.

Consultar esta tabla es bastante sencillo basta con usar la consulta:

SELECT * FROM INFORMATION_SCHEMA.EVENTS

Lo que le mostrara una salida similar a la figura:

Estatus de Eventos
Estado de los Eventos

Esto le presentara todos los eventos que se hallan creado la declaración de estos, el intervalo de ejecución, la fecha de arranque y, aun mas útil, la fecha y hora de la ultima ejecución del mismo, toda esta información nos puede servir para detectar una variedad de problemas, desde un evento mal programado a que el Scheduler del MySQL se halla detenido.

Espero que esta información les sea de utilidad y nos vemos en la próxima entrada.

Error 2006 en MySQL

Al momento de llevar a producción una aplicación que acceda a bases de Datos MySQL algo que uno debe de esperar es lo inesperado, desde los problemas mas obvios a los errores mas pintorescos que se pueda imaginar, este es uno de los ultimos.

En el servidor MySQL el error “MySQL server has gone away (error 2006)” se le presentara cuando el tamaño de los datos a procesar exceda el maximo tamaño de paquete que pueda manejar o el servidor tome mas tiempo de lo permitido procesando una consulta en particular, en mi propia experiencia estos casos pueden presentarse cuando el MySQL server se esta ejecutando en una maquina con recursos mas bien modestos.

En cualquiera de los casos la solución de este error es relativamente sencilla, basta con aumentar el tamaño maximo de los paquetes de datos y/o el tiempo de espera para la respuesta del servidor, ambas opciones pueden modificarse desde “Options File” en la configuración del servidor MySQL, como se ve en las figuras 1 y 2.

Figura 1: Tamaño maximo permitido
Figura 1: Tamaño maximo permitido.
Figura 2: Tiempo de espera
Figura 2: Tiempo de espera

Figura 2: Tiempo de Espera.

El modificar estas opciones deberia corregir el problema por completo, pero no tendran ningun efecto hasta que reinicie el servidor MySQL de modo que arranque con las nuevas opciones, si esta en un entorno de producción debe tener cuidado al hacer esto, ya que si bien el reinicio es relativamente veloz, podria causar problemas a aplicaciónes que esten en uso en ese momento o interrumpir servicios, para reiniciar el servidor vaya a “Startup/Shutdown” y, como se ve en la figura 3, desde ahi podria apagar y volver a iniciar el servidor MySQL

Figura 3: Inicio / Apagado de MySQL
Figura 3: Inicio / Apagado de MySQL

Espero que esta entrada halla sido de utilidad y nos vemos en la proxima.

Referencias:

How to fix “MySQL server has gone away” (error 2006)