Backup de MySQL con Java

De ChuWiki

Veamos cómo hacer un backup de una base de datos MySQL con Java y cómo restaurarlo después. Para ello, usaremos los ejecutables que nos ofrece MySQL para backup (mysqldump) y para ejecutar luego el fichero de backup generado (mysql). Puedes ver estos comandos en Volcado de seguridad en MySQL con mysqldump


El código completo en BackupMySQL.java

Lanzar ejecutables externos desde java[editar]

Para lanzar ejecutables externos desde java, tenemos la clase Runtime, que se usaría así

Process p = Runtime.getRuntime().exec("ejecutable externo"); 

Los ejecutables que querremos ejecutar son los siguientes. Para backup

mysqldump -u root -ppassword database > fichero_backup.sql

y para restaurar la base de datos

mysql -u root -ppassword database < fichero_backup.sql

El problema con Runtime es que las redirecciones de o a fichero ( "> fichero_backup.sql" y "< fichero_backup.sql" ), no funcionan. La salida y entrada estándar del ejecutable se redirige a java, y no a o desde el fichero. Por ello, no podemos ejecutar el comando con estas redirecciones, sino que debemos ejecutar el comando directamente, así

mysqldump -u root -ppassword database

o bien

mysql -u root -ppassword database

y desde java encargarnos de leer su salida o enviarle el contenido del fichero. Veamos el código.

backup[editar]

El código para hacer el backup puede parecerse a este

private static void backup() {
   try {
      Process p = Runtime
            .getRuntime()
            .exec("C:/Aplicaciones/wamp/bin/mysql/mysql5.1.36/bin/mysqldump -u root -ppassword database");

      InputStream is = p.getInputStream();
      FileOutputStream fos = new FileOutputStream("backup_pruebas.sql");
      byte[] buffer = new byte[1000];

      int leido = is.read(buffer);
      while (leido > 0) {
         fos.write(buffer, 0, leido);
         leido = is.read(buffer);
      }

      fos.close();

   } catch (Exception e) {
      e.printStackTrace();
   }
}

Ejecutamos mysqldump poniendo su path completo si no lo tenemos en el path de búsqueda de ejecutables, poniendo todas las opciones de este ejecutable que queramos. Es importante poner el usuario y password para evitar que nos lo pregunte.

Para obtener la salida de este comando, pedimos el InputStream al Process que obtenemos al ejecutarlo. De este InputStream iremos leyendo la salida estándar del comando mysqldump. Sólo tenemos que hacer un bucle de lectura e ir guardando lo que leemos en un fichero, que será nuestro fichero de backup (backup_pruebas.sql)


Restaurar[editar]

El código para restaurar la copia puede ser como este

private static void restore() {
   try {
      Process p = Runtime
            .getRuntime()
            .exec("C:/Aplicaciones/wamp/bin/mysql/mysql5.1.36/bin/mysql -u root -ppassword database");

      OutputStream os = p.getOutputStream();
      FileInputStream fis = new FileInputStream("backup_pruebas.sql");
      byte[] buffer = new byte[1000];

      int leido = fis.read(buffer);
      while (leido > 0) {
         os.write(buffer, 0, leido);
         leido = fis.read(buffer);
      }

      os.flush();
      os.close();
      fis.close();

   } catch (Exception e) {
      e.printStackTrace();
   }
}

Ejecutamos, como antes, el comando mysql con todas las opciones que queramos. Debemos alimentar la entrada estándar de este comando con el fichero de backup que obtuvimos en el paso anterior. Para ello, del Process que se obtiene al ejecutar el ejecutable, se pide el OutputStream, donde debemos ir metiendo el contenido del fichero.

Para ello, abrimos el fichero de backup, en un bucle vamos leyéndolo y escribiendo en el OutputStream del Process, hasta finalizar el fichero.

Aquí hay un detalle importante (entre otros muchos). En el ejecutable "mysql .... database" hemos puesto el nombre de la base de datos a la que nos conectamos. Esto implica que esa base de datos existe y que el fichero de backup no la crea. Si hubiesemos puesto opciones para que mysqldump creara la base de datos, no deberíamos conectarnos a ella con "mysql ... database", sino que bastaría con poner sólo el usuario y password y otras opciones que necesitemos.

Lectura de errores[editar]

Al ejecutar estos comandos con Runtime, pueden producirse errores. Para poder depurar o mostrarlos en algún sitio si se producen, es interesante pedir el ErrorStream del Process y leerlo. Puesto que no podemos leer/escribir simultáneamente de varios streams, es necesario hacerlo con un hilo. La siguiente clase puede ayudarnos a hacerlo

public class HiloLector extends Thread {
   private InputStream is;

   public HiloLector(InputStream is) {
      this.is = is;
   }

   @Override
   public void run() {
      try {
         byte[] buffer = new byte[1000];
         int leido = is.read(buffer);
         while (leido > 0) {
            String texto = new String(buffer, 0, leido);
            System.out.print(texto);
            leido = is.read(buffer);
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

Es simplemente una clase que extiende de Thread y que en su constructor recibe un InputStream. Cuando arranquemos el hilo, ira leyendo del InputStream y sacando por pantalla lo leido. En los dos procesos anteriores de backup y de restaurar, sólo tenemos que poner esta línea

new HiloLector(p.getErrorStream()).start();

inmediatamente detrás de las llamadas a Runtime.getRuntime().exec("..."), de forma que veremos en consola si se produce algún error en el proceso, como opciones de los comandos mysqldump o mysql incorrectas.