Almacenar datos en PhoneGap/Cordova usando Web SQL

Si en el anterior post analizaba una forma sencilla de almacenar información local con PhoneGap/Cordova usando localStorage, hoy vamos a ver una alternativa para almacenar datos algo más compleja pero a la vez más potente: Web SQL.

OJO: Antes de seguir leyendo, es importante que sepas que la especificación Web SQL Database ya no está soportada por el W3C, aunque eso no quiere decir que no se pueda utilizar. Está soportada por los principales navegadores móviles y además, si lo vas a usar con PhoneGap/Cordova, la propia librería se encarga de dar soporte en aquellos navegadores que no lo soportan de forma nativa.

Web SQL Database

Como te puedes imaginar, estamos hablando de una base de datos SQL. La mayoría de los navegadores la implementan usando SQLite, cuyo dialecto de SQL es bastante completo.

La información almacenada sobrevive a reinicios de aplicación y es almacenada por el navegador que esté usando PhoneGap/Cordova, igual que en el caso del localStorage, por lo que tampoco será fácil compartirla entre distintas aplicaciones.

El API para manejar la base de datos no es excesivamente complicada y podéis encontrar información en la documentación de Cordova y el propio W3C, pero por simplificar las cosas, los pasos para trabajar con Web SQL son los siguientes.

Lo primero que hace falta es conectarse a la base de datos o crear una nueva usando la función openDatabase:

var db = openDatabase('MyDB', '1.0', 'My Sample DB', 100 * 1024);

Es necesario indicar el nombre de la base de datos, la versión que esperamos encontrar de la base de datos, una descripción y el tamaño estimado que tendrá la base de datos.

La versión nos ayuda a gestionar los cambios de esquema que podamos tener entre versiones de aplicación. Si intentamos abrir una base de datos usando una versión incorrecta, se generará un error y deberemos usar la función changeVersion para actualizar la versión y aplicar las migraciones necesarias.

Una vez que tenemos un objeto Database, podemos lanzar ejecutar transacciones sobre la base de datos usando el método db.transaction(...):

db.transaction(function(tx) {
    tx.executeSql('create table if not exists People(id, name, age)');
    tx.executeSql('insert into People(id, name, age) values (1, "Marujita", 105)');
}, errorCB, successCB);

El método transaction recibe hasta tres callbacks, una con lo que queremos ejecutar dentro de la transacción, otra que se invocará en caso de error y otra que se invocará si todo ha ido bien.

Para evitar problemas con SQL-injection, se deben utilizar consultas parametrizadas y evitar la concatenación de strings:

tx.executeSql('insert into People(id, name, age) values (?,?,?)', 
              [1, "Marujita", 105]);

La lectura de datos se realiza invocando el método executeSql con una callback que recibe, además de la transacción en curso, un SQLResultSet que nos permite acceder a la información leída:

tx.executeSql('select id, name, age from People where age > ?', [100], function(tx, rs) {
    for (var i = 0; i < rs.rows.length; i++) {
        var p = rw.rows.item(i);
        console.log(p.id + ' ' + p.name + ' ' + p.age);
    }
}, errorCB);

El SQLResultSet tiene la propiedad rows que contiene los registros cargados. Ojo, que aunque parece un array no lo es y para poder acceder al registro i-ésimo hace falta utilizar la función rows.item(i) en lugar del indexador. Como siempre, podemos utilizar una función callback para que nos notifiquen de posibles errores.

Ventajas e Inconvenientes

Se trata de una base de datos relacional SQL con su esquema y esas cosas que ya no están de moda. Eso será una ventaja para algunos y una desventaja para otros, pero sin duda se trata de la característica principal de este almacenamiento.

Al tratarse de una base de datos relacional, es mucho más fácil realizar consultas arbitrarias que con localStorage, que era un almacenamiento clave/valor y sólo podía ser consultado por clave.

A cambio, su manejo es más complicado, sobre todo porque todo es asíncrono, por lo que es fácil acabar perdiéndose en un millón de callback. No he probado a mezclarlo con promises o usar alguna librería como persistence.js por encima, pero tal vez eso lo hiciera más manejable.

Por último, no hay que olvidar que como avisaba al principio del post, el W3C ha dejado de mantener esta especificación; aunque ahora sea viable seguir usándolo, no sé hasta cuando será soportado por los navegadores o PhoneGap/Cordova.

35 comentarios en “Almacenar datos en PhoneGap/Cordova usando Web SQL

  1. Con este codigo puedo almacenar datos en una tablet android? si hago un apk por ejemplo

  2. disculpa mi ignorancia, no se del tema, pero si tengo una enorme inquietud..
    cual seria el repositorio de la informacion, es decir a donde se almacena fisicamente los datos. y podria crear una bd sin codigo y consultarla con cordova?

  3. No estoy seguro de entender tus dudas.

    La base de datos se almacena en el equipo local, no en el servidor remoto. Si por físicamente te refieres al nombre del fichero, eso depende de la implementación de cada navegador y no debería ser algo de lo que dependieras.

  4. Estoy realizando una aplicacion en cordova que utiliza una base de datos. La misma aplicacion tiene un servicio (escrito en java nativo) que tambien necesita acceder a la misma base de datos. Para este caso en importante saber la localizacion fisica de la base de datos.

  5. No creo que puedas acceder desde el servicio a la BD de cordova. ¿Por qué no lo haces al revés? Ya que tienes escrito el código en java para tocar la base de datos desde el servicio, puedes encapsular ese código en un plugin (como se explica aquí) y utilizarlo desde la aplicación cordova. Ten en cuenta que tendrás que tener cuidado con la sincronización del acceso a la BD porque SQLite no es muy amigo de accesos concurrentes.

  6. Hola!creo saber la dirección donde se guardan las bases de datos probá:
    -En eclipse seleccionar DDMS en la esquina superior derecha, luego file explorer,todo esto con la máquina virtual ejecutandose.
    -Esto nos da acceso al explorador de archivos del dispositivo virtualizado.
    -En la ruta /data/data/.com.(nombre del paquete de trab de la aplicacion)/app_database/databases.db se encuentra donde y con q nombre se
    guardo nuestra DB. Se puede utilizar el sqlite manager del mozilla para abrir el archivo.
    -la DB se nombra con otro nombre, en mi ejemplo esta en app_database/file__0 y el nombre es 0000000000000001.db
    -Se puede extraer el archivo con las opciones de arriba a la derecha del explroador.

  7. que tal, se puede crear, leer, modificar y borrar archivos xml? que esten porejemplo en la carpeta downloads?
    tienes una idea de como seria?

    salu2!

  8. Hola, tienes idea de que versión de Android soportan el uso de web sql con phonegap?
    He hecho pruebas desde el Emulador con versión 2.2 y el código no funciona, y con versión 4.0 y si funciona. Pero el Api de phonegap no hace referencia a que versiones funciona, solo colocan Android, por lo que doy por entendido que funciona en todas las versiones, no?

  9. Jhonnatan, según esta página, web sql debería funcionar a partir de Android 2.1 (http://caniuse.com/sql-storage).

    Teniendo en cuenta que phonegap al final lo que hace es aprovechar el propio browser de la plataforma, debería funcionar también con phonegap. Tal vez haya algún problema con las APIs concretas y en android 2.2 haya alguna diferencia con respecto al API usada en el ejemplo (que, por cierto, era con un android 2.3).

  10. Ok listo, muchas gracias! ya me di cuenta del error, necesita permiso en el config.xml :) Gracias por la respuesta. Por cierto el tamaño estimado de la base de datos es en mega, cierto?

  11. Buenas tardes gracias por el tutorial!
    Alguna manera de exportar web sql a un fichero que posteriormente pueda ser explorado? Estoy creando una aplicacion en Phonegap Para Android y sería interesante poder realizar una copia de la base de datos para analizarla desde un PC.

    Gracias!

  12. hola,
    por lo que dice BRian, al almacenarse en una carpeta del sistema, supongo que otro programa puede acceder a la bbdd. No es muy seguro no? Hay alguna manera de elegir donde guardar almacenar los datos en otro sitio? o encriptar los datos.
    gracias

  13. Tienes la misma seguridad que con cualquier otra aplicación que escriba en flash. Si otra app tiene permiso para leer datos, podrá leerlos.

    Si te preocupa mucho esto, podrías emplear alguna librería de encriptación, ya sea directamente en javascript, o creando un plugin de PhoneGap que te permita cifrar y descifrar desde código nativo.

  14. Hola,
    gracias por el post!
    Estoy haciendo una app en la que necesito guardar datos que el usuario introducirá a través de un formulario en la base de datos local de la aplicación. En mis experimentos con webSQL, al cerrar la aplicación, estos datos introducidos han sido borrados. Es este el comportamiento normal de web SQL? Para conseguir lo que necesito tendría que recurrir a local storage? Gracias de antemano!

  15. Hola Marta,

    No debería pasar. Se supone que webSQL es un almacenamiento persistente y sobrevive a distintas ejecuciones de la aplicación. ¿Qué navegador y sistema operativo estás usando?

    Un saludo,

    Juanma

  16. Hola, tengo una duda. Si por ejemplo quiero crear una base de datos y quiero que esa base de datos la consulte la aplicacion del lado del cliente y que al consultarla ya tenga datos y no que empiece de cero. Se puede? Se puede crear un archivo de base de datos al cual haga conexion y consulte de él o tiene que empezar de cero siempre?

  17. Hasta donde yo sé, si utilizas WebSQL no puedes «descargar» una base de datos pregenerada y te tocaría hacer la inserción en el cliente.

    Una posible alternativa sería ir por la vía del plugin, y crear un plugin que acceda a una base de datos del sistema de archivos (independiente del navegador). Así si que podrías descargar una base de datos inicial desde el servidor, pero te obliga a implementar la parte nativa del plugin en todas las plataformas que quieras soportar.

  18. Cuando se dice que es relacional, es completamente relacional?
    tiene Foreign key, eliminacion en cascada, Upgrade en cascada.. relaciones de distintas cardinalidades y eso?

  19. camuschino, es todo lo relacional que sea la implementación que haya por debajo. La mayoría de navegadores que lo soportan usan SQLite, así que imagino que tendrás disponibles las características que existan en SQLite.

  20. Hernando A. dijo:

    Buenos dias, muy buen post.
    tengo un problema, algo parecido a lo de Martha, cuando cierro la aplicación se me borran los datos, estoy utilizando 4.2.2

  21. Hola Hernando,

    La verdad es que no sé qué puede estar pasando. Deberían mantenerse los datos entre ejecución y ejecución. ¿Las páginas web van embebidas en el apk o se las baja de un servidor? ¿Estás desplegando distintos apks, o es sobre el mismo?

    Un saludo,

    Juanma

  22. Buenas a todos,
    estoy creando un app android con visual studio 2013. tengo un problema: tengo una base da datos .db con tablas y datos. lo que pasa es que no se en que carpeta tengo que colocar mi BD.
    Alguien tiene una idea? crie una pasta data/data/…. y no consegui si alguien pudiera ayudar les agradesco.

    gracias!

  23. Ever Leandro Santiesteban Jimenez dijo:

    Gente estaba creando aplicaciones usando phoneGgap y me parecio buena idea desarrollar un framework o libreria que me ayudara a la creacion de Bases de datos usando web sql asi que cree un index con algunas vistas desarrollado en javascript que me facilita mucho el trabajo si alguien esta interesado puede ponerse en contacto conmigo a mi correo elsantiesteban@estudiantes .uci.cu its’ free lo hago solo para ayudar a los que lo necesiten.

  24. Hola amigo.
    Primero que nada, felicidades por tus post, son muy buenos, en verdad.
    Tengo una duda, estoy creando una app basada en cordova, para android, el problema es el offline. Veo que con web-sql, eso se puede resolver. Quisiera saber si se puede sincronizar la información de la base de datos local (web-sql) con alguna externa (mysql), por medio de javascript, lo pienso hacer con ajax, que en el momento en que haya conexión se consulten todos los datos de la base de datos local y se envíen para cargarlos a la base que está en el servidor, la pregunta es: ¿Existe algún otro recurso para la sincronización cuando el dispositivo pase de offline a online?

  25. jose luis castillo hernandez dijo:

    jose luis
    tengo una aplicacion en android apk la instalo pero cuando la ejecuto
    no me aparece los datos de la aplicacion tengo una bd desde un servidor pero no me carga cuando ejecuto la aplicacion y tengo que cargar desde el servidor insertando la informacion

  26. Buenas tardes, estoy desarrollando una aplicación web para que pueda ser compatible con ios y android, mi consulta es si hago uso de websql, los datos almacenados en que momento se borran al cerrar el navegador o limpiar el historial, tengo pensado hacer un respaldo de las tablas de websql cuando el usuario tenga acceso a internet.

    Gracias.

  27. Hasta donde yo sé, los datos se borran cuando el usuario decide borrar datos almacenados (en Android se llama así, no sé en iOS), no cuando cierra el navegador ni cuando borra el historial.

  28. Hola. Gracias por la información. Tengo un problema a la hora de almacenar datos en WebSQL en una aplicación phonegap. No se insertan los datos correctamente.

    Si pruebo en Chrome, abriendo mi index.html directamente en él, funciona de maravilla, pero en Phonegap no, a pesar de que compruebo mediante logs que el dispositivo está listo (de hecho, no se ejecuta nada hasta que se detecta deviceready), e incluso entro dentro de los callbacks de éxito de las inserciones de datos (estos me llegan previamente desde un servidor remoto).

    Como digo, todo ello en Chrome va perfecto, pero en Phonegap no hay manera. Llevo varios días bloqueado con este tema y no sé por dónde tirar.

Comentarios cerrados.