Archivo de la etiqueta: Bases de Datos

Adobe AIR V – Trabajando con bases de datos locales sqlite

Llegamos al penúltimo capítulo de esta serie acerca de Adobe AIR. Hoy veremos como trabajar en local con datos persistentes de manera que podamos recuperarlos en otras sesiones. Al decir en local me refiero a que no se necesita conexión a Internet para salvaguardarlos, no se utilizará una base de datos remota sino el propio ordenador del cliente.

A diferencia de las aplicaciones Flash embebidas en un navegador, AIR permite el acceso completo al sistema de archivos del sistema operativo, no tiene las limitaciones de la máquina virtual Flash ni las políticas de seguridad, así que podemos crear, abrir, modificar y guardar cualquier archivo.

Si unimos todo esto con sqlite obtenemos lo que buscamos ya que AIR trae soporte nativo para sqlite con lo que guardar y consultar datos con sentencias sql no será un problema, más sencillo imposible.

AIR permite dos modos de trabajo con sqlite, síncrono y asíncrono. La diferencia es obvia, en el primer tipo se espera a que la ejecución de las instrucciones sql termine para continuar la ejecución de la aplicación, mientras que en el modo asíncrono se utilizan eventos que se disparan cuando se da por finalizada la consulta. En modo sincrono debemos ejecutar todo enjaulado en estructuras try/catch para prevenir errores y excepciones.

Aunque puedes crear la base de datos directamente desde la propia aplicación con sentencias CREATE TABLE, yo prefiero distribuir la aplicación con la base de datos ya creada, es mucho más cómodo. Para crearlas suelo usar dos utilidades:

También puedes hacer tu propia aplicación AIR para gestionar bases de datos sqlite, no conozco ninguna pero sería muy útil. ¿Quién se atreve? 🙂

Con cualquiera de ellas podremos crear la estructura de nuestra base de datos que copiaremos en el directorio del código fuente, para que al compilarla y empaquetarla se distribuya con ella.

Como no todos los sistemas operativos permiten a cualquier usuario escribir en la ruta de instalación de las aplicaciones, lo mejor y más recomendable es copiar la base de datos «base» en la carpeta de usuario del cliente que está ejecutándola ya que ahí siempre tiene permisos. Para hacerlo AIR nos provee de todos los mecanismos necesarios.

Con los métodos userDirectory y applicationDirectory de la clase File accedemos a las rutas de usuario y de la aplicación respectivamente independientemente del sistema operativo sobre el que está corriendo la aplicación, con lo cual hacemos el proceso completamente transparente.

var a:File=File.userDirectory.resolvePath("basedatos.db");
if(!a.exists){
    var b:File=File.applicationStorageDirectory.resolvePath("basededatos.db");
    b.copyTo(a, true);
}

Sencillo y evidente, sobran más explicaciones. Sabiendo esto es ya muy fácil conectar a la base de datos. Utilicemos el método síncrono antes comentado.

private var dbFile:File;
private var conn:SQLConnection;
private var q:SQLStatement;  

private function iniciaDB():void {
    var dbFile:File=File.userDirectory.resolvePath("basededatos.db");
    if(!dbFile.exists){
        var b:File=File.applicationStorageDirectory.resolvePath("basededatos.db");
        b.copyTo(dbFile, true);
    }
    conn = new SQLConnection();
    try{
        conn.open(dbFile);
    }catch (error:SQLError){
        Alert.show("ERROR ABRIENDO BBDD "+error.message+" "+error.details);
    }
}

¡Ya estamos dentro de la base de datos! Sólo nos queda ejecutar consultas y recuperar los resultados. No tiene mucha ciencia. Veamos un ejemplo para que queda bien claro.

var q:SQLStatement;
var result:SQLResult;

q.text = "SELECT campo1, campo2 FROM tabla";

try{
   q.execute();
   result=q.getResult();
   if(result.data){
     var numResults:int = result.data.length;
     for (var i:int = 0; i < numResults; i++){
        var r:Object = result.data[i];
        //accedemos a los campos desde el objeto, r.campo1, r.campo2
     }
   }
}catch (error:SQLError){
  //la consulta nos ha devuelto un error
}

Eso es todo como iniciación sqlite desde AIR. Del mismo modo se pueden ejecutar instrucciones INSERT, DELETE

A partir de aquí puede seguir cualquiera 😛 .

En el próximo y último capítulo veremos como hacer ventanas de notificación instantáneas y no intrusivas, del estilo de los avisos de conexión del Messenger 😉 .

Copias de seguridad de bases de datos

A través de Pensamientos Ágiles llego a un artículo donde explican una interesante manera de hacer backups de bases de datos Mysql utilizando subversion. La idea es excelente, pero me plantea una serie de dudas si se trata de bases de datos de gran tamaño. Creo que es genial para mantener la estructura de la base de datos de un proyecto y tener controlados los cambios que se realizan sobre ella, pero mantener también los datos… no acabo de verlo.

En uno de mis proyectos tengo una base cuyo dump ocupa alrededor de 1Gb. Yo, sinceramente, no veo coherente mantener semejante archivo en svn. La idea es excelente y para bases de datos «pequeñas» creo que sí es útil, habría que decidir, en todo caso, qué entendemos por «pequeñas«. Pero insisto, no lo veo para archivos grandes, y 1Gb, tengamos el criterio de grande/pequeño que tengamos, es un archivo grande.

Normalmente lo que hago para hacer los backups es sacar un dump de cada base de datos, de manera que pueda recuperar cualquiera de ellas, y comprimir el resultado con bzip2. ¿Por qué bzip2 y no gzip? Simplemente por el nivel de compresión. En su día hicimos pruebas con ámbos sistemas y bzip2 salía mejor parado. Éstos son los resultados que obtendríamos hoy en día con la compresión estándar de ámbos sistemas:

-rw-r--r--   1 osus   users  1023246033 Feb  2 01:50 bbdd.sql
-rw-r--r--   1 osus   users   141481434 Feb  2 01:50 bbdd.sql.bz2
-rw-r--r--   1 osus   users   190733372 Feb  2 01:50 bbdd.sql.gz

Con bzip2 el backup pesa unos 50mb menos.

El script que utilizo para hacer backups de base de datos es más o menos lo que suele hacer la mayoría de la gente:

#!/bin/sh
dia=`date +%w`
for i in ` /usr/bin/mysql -N --execute='show databases;' `
do
echo "Haciendo backup de $i"
/usr/bin/mysqldump -C --opt $i > /backup/bbdd/$dia/$i.sql
bzip2 -fz /backup/bbdd/$dia/$i.sql
done

En otras palabras, mantengo las copias completas de los últimos siete días, semanalmente se se reemplazan por las del día en que nos encontramos. En la carpeta del día correspondiente genero los dumps comprimidos de todas las bases de datos.

El último paso es copiar los dumps del día a otra máquina. La tarea que se ejecuta diariamente lanza el proceso una vez termina de crear los backups. Esto lo hacemos a dos máquinas distintas. La primera es una máquina externa y se envían por ssh desatendido, utilizando claves públicas, de manera que la máquina remota no solicita la clave del usuario. La segunda es una máquina de nuestra oficina con la que tenemos una vpn que se levanta antes del backup, se copia con ssh destendido también y se cierra al terminar. En ésta máquina de la oficina hay otra tarea que diariamente restaura el backup de ciertas bases de datos en su Mysql local matando así dos pájaros de un tiro: por un lado tenemos la base de datos de desarrollo casi idéntica a la de producción, faltarían sólamente los últimos datos del día, y por otro lado nos aseguramosn de que los backups que se realizan son correctos ya que en caso contrario fallaría la restauración.

Hasta ahora nos ha funcionado bien el sistema. En alguna ocasión hemos tenido que recuperar alguna tabla de ciertas bases de datos y no hemos tenido excesivos problemas, todo ha funcionado a la perfección.

Vuelvo a repetir que esto no es una crítica al sistema del subversion, todo lo contrario, la idea me parece cojonuda, pero creo que habría que puntualizar o estudiar bien la viavilidad en ciertos escenarios.