Backup de MySQL con Java
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.