Almacenamiento con HTML5: Almacenamiento Sql
Publicado el 21/04/2010 en Programación por Jose M. Carbonell
Ingeniero de sistemas y apasionado de Ruby on Rails, desarrollo web y metodologías ágiles. Uno de los primeros en utilizar Ruby on Rails Rails en España.
Este artículo es el segundo de una serie de 3 artículos:
- Almacenamiento con HTML: Almacenamiento local
- Almacenamiento con HTML: Almacenamiento SQL
- Almacenamiento con HTML: Ejemplo de aplicación
Base de datos local
Otro tipo de almacenamiento disponible en la especificación de HTML5 es el Web SQL Database o Base de Datos Web Sql. Este tipo de almacenamiento define una API para almacenar datos en bases de datos locales que pueden ser consultadas usando una variante de SQL.
Esta funcionalidad todavía no está implementada en todos los navegadores. De hecho, los únicos navegadores que la implementan, a fecha de hoy, son aquellos que utilizan Webkit como motor de renderizado. Entre ellos, Google Chrome, Safari, Safari Mobile, etc..
Mozilla Firefox todavía no tiene bases de datos locales y posiblemente Internet Explorer no la soporte jamás.
Nota que para los ejemplos de este artículo necesitarás un navegador compatible y que HTML5 está siendo desarrollado todavía, por lo que lo explicado aquí puede cambiar en el futuro.
Conectando
Lo primero es abrir una conexión con la base de datos. Esto se realiza con la función openDatabase(name, version, description, size). openDatabase() necesita 4 argumentos:
-
nameEs el nombre de la base de datos. -
versionLa versión de la base de datos. -
descriptionEs una descripción dada a la base de datos que puede servir para informar del propósito de la base de datos. -
sizeEs un tamaño aproximado del tamaño de la base de datos. Especialmente útil para que el navegador prepare el espacio necesario para almacenar los datos. Este tamaño es variable.
Por ejemplo:
var db = openDatabase("DemoSqlStorage", "1.0", "Base de datos de prueba", 5*1024*1024);
En caso de que ocurra algún error, y no se pueda conectar con la base de datos, openDatabase() devolverá null por lo que podemos comprobar si todo ha ido bien:
var db = openDatabase("DemoSqlStorage", "1.0", "Base de datos de prueba", 5*1024*1024);
if (db){
alert("La conexión se ha realizado correctamente.");
}else{
alert("No se ha podido establecer conexión con la base de datos.");
}
Un error puede ser que el navegador nos deniegue el acceso por cuestiones de seguridad o si hemos alcanzado el tamaño máximo de espacio disponible en el dispositivo.
Transacciones
Las consultas se realizan sobre el objeto devuelto por la función openDatabase() por medio de la función transaction. transaction() puede recibir de 1 a 3 argumentos:
-
transaction_function(tx)Se trata de una función anónima que se encarga de realizar la transacción. -
error_callback(tx)Se trata de una función anónima que se ejecuta en caso de que ocurra un error en la transacción y la función de la transacción no tiene ningún callback para el manejo de errores. -
success_callback(tx)Se trata de una función anónima que se ejecuta si la transacción termina correctamente y la función de transacción no tiene ningún callback para el manejo de éxitos.
Estas funciones pueden pueden recibir la transacción como argumento.
Ejemplo:
error_callback = function(tx){ alert("Error en la transacción"); };
success_callback = function(tx){ alert("Transacción correcta"); };
db.transaction(function(tx){}, error_callback, success_callback)
Consultas
Las consultas SQL se realizan en el contexto de una transacción mediante la función executeSql(). Esta función puede recibir hasta 4 argumentos:
sql Es una consulta SQL.
executeSql('SELECT title FROM movies');
args Permite sustituir variables en las consultas SQL sin riesgos de vulnerabilidades de inyección SQL:
var id = 1202;
executeSQL('SELECT title FROM movies WHERE id = ?', [id]);
success_callback(tx, result) Función que se ejecuta cuando la consulta se ejecuta correctamente. Recibe como argumentos la transacción y el objeto del resultado:
var id = 1202;
executeSQL('SELECT title FROM movies WHERE id = ?', [id], function(tx, result){});
error_callback(tx, error) Función que se ejecuta cuando la consulta se ejecuta correctamente. Recibe como argumentos la transacción y el objeto del error:
var id = 1202;
executeSQL('SELECT title FROM movies WHERE id = ?', [id], function(tx, result){}, function(tx, error){});
Consultas con éxito
En el callback success_callback(tx, result), result es un objeto con los siguientes atributos:
-
insertId: Es el id de la fila insertada en caso de haberse insertado una fila o de la última fila si se han insertado varias. Si no se ha insertado nada lanzará una excepción. -
rowsAffected: Devuelve el numero de filas afectadas por la consulta SQL. Para consultas SELECT su valor es 0, ya que consultar no modifica ninguna fila. -
rows: Devuelve una lista ordenada de las filas devueltas por la consulta SQL. Esta lista tiene la siguiente interfaz:
lengh: Número de filas.
item(n): función para obtener la fila de un índice n dado.
Consultas erróneas
En el callback error_callback(tx, error), error es un objeto con los siguientes atributos:
code: Código de error.message: El mensaje de error.
Ejemplo de una consulta errónea:
var db = openDatabase("DemoSqlStorage", "1.0", "Base de datos de prueba", 5*1024*1024);
db.transaction(function(tx){
tx.executeSql('select * from productos' ,[],
function(tx, result){
alert('Consulta exitosa');
},
function(tx, error){
alert('Se ha producido el siguiente error:\n' + error.message);
}
);
});
Ejemplo de una consulta exitosa:
var db = openDatabase("DemoSqlStorage", "1.0", "Base de datos de prueba", 5*1024*1024);
db.transaction(function(tx){
// En este caso creamos la tabla antes de consultarla
tx.executeSql('CREATE TABLE productos (id real unique, name text)');
tx.executeSql('select * from productos' ,[],
function(tx, result){
alert('Consulta exitosa\n '+result.rows.length + ' filas encontradas');
},
function(tx, error){
alert('Se ha producido el siguiente error:\n' + error.message);
}
);
// Borramos la tabla
tx.executeSql('DELETE productos');
});
Inserciones
La inserción de filas en la base de datos se realiza de forma segura evitando inyecciones de SQL:
var nombre = "Producto 1";
var precio = 220;
db.transaction(
function(tx){
tx.executeSql("INSERT INTO productos (name, price) values (?,?)", [nombre, precio]);
}
)
En este ejemplo, el valor de nombre y precio sustituirán los signos de interrogación de la consultadas dando como resultado:
INSERT INTO productos (name, price) values ("Producto1", 220);
Ejemplo
Lo siguiente es un ejemplo con las operaciones más frecuentes:
var db = openDatabase("DemoSqlStorage", "1.0", "Base de datos de prueba", 5*1024*1024);
var sql = "CREATE TABLE productos(id REAL UNIQUE, name TEXT, price FLOAT, timestamp REAL)";
db.transaction(
function(tx){
tx.executeSql(sql, [],
function(tx, result){
alert('Tabla creada');
},
function(tx, error){
alert('Error: ' + error.message);
}
);
}
);
var sql = "SELECT count(*) FROM productos";
db.transaction(
function(tx){
tx.executeSql(sql, [],
function(tx, result){
if (result.rows.length == 1){
alert('Ejecución correcta.\n' + result.rows.item(0)['count(*)'] + ' productos encontrados.');
}
},
function(tx, error){
alert('Error: ' + error.message);
}
);
}
);
var sql = "SELECT * FROM productos order by timestamp DESC limit 5";
db.transaction(
function(tx){
tx.executeSql(sql, [],
function(tx, result){
if (result.rows.length > 0){
var size = result.rows.length;
var str = "";
for(var i=0; i < 5 && i < size; i++){
var product = result.rows.item(i);
str += "Producto: " + product.name + " - Precio: " + product.price + "\n";
}
alert('Ejecución correcta.\nÚltimos ' + result.rows.length + ' productos.\n' + str);
}else{
alert('Ejecución correcta.\nTodavía no hay productos.');
}
},
function(tx, error){
alert('Error: ' + error.message);
}
);
}
);
var name = prompt("Introduce el nombre del producto");
var price = prompt("Introduce el precio del producto");
if (!!name && !!price){
var sql = "INSERT INTO productos (name, price, timestamp) values (?,?,?)";
db.transaction(
function(tx){
tx.executeSql(sql, [name, price, new Date().getTime()],
function(tx, result){
alert('Ejecución correcta.\n' + result.rowsAffected + ' productos afectados');
},
function(tx, error){
alert('Error: ' + error.message);
}
);
}
);
}else{
alert("Los valores no son correctos, no puede crearse el producto.");
}
var query = prompt("Busqueda por nombre");
var sql = "SELECT * FROM productos where name LIKE ?";
this._db.transaction(
function(tx){
tx.executeSql(sql, ["%" + query + "%"],
function(tx, result){
if (result.rows.length > 0){
var size = result.rows.length;
var str = "";
for(var i=0; i < 5 && i < size; i++){
var product = result.rows.item(i);
str += "Producto: " + product.name + " - Precio: " + product.price + "\n";
}
alert('Ejecución correcta.\n' + result.rows.length + ' productos encontrados con ' + query + '.\n' + str);
}else{
alert('Ejecución correcta.\nNo se han encontrado productos.');
}
},
function(tx, error){
alert('Error: ' + error.message);
}
);
}
);
var sql = "DROP TABLE productos";
this._db.transaction(
function(tx){
tx.executeSql(sql, [],
function(tx, result){
alert('Ejecución correcta.\n' + result.rowsAffected + ' filas afectadas.');
},
function(tx, error){
alert('Error: ' + error.message);
}
);
}
);







hola que buenos ejemplos es lo mejor que he encontrado ta cool