Entradas etiquetadas como ‘datos’

Frases con historia (XV)

He viajado a lo largo y ancho de este país y he hablado con las personas más preparadas y puedo asegurar que el procesamiento de datos es una moda pasajera que no durará más de un año.

Editor mercantil de Prentice Hall, 1957.

Concurrencia optimista en bases de datos

Red de datos

Red de datos

En un entorno multiusuario en el que varios puestos de red atacan un mismo banco de datos se da siempre un problema que un buen programador ha de solventar de la manera más elegante. El problema consiste en lo que se ha dado en llamar concurrencia de datos, es decir, si un usuario lee un registro de una tabla con el objeto de modificarlo, en ese preciso momento es probable que otro usuario recabe el mismo registro para modificarlo también. En el caso de que el segundo acceso modifique los datos antes que el primero, se produce lo que se conoce como una infracción, ya que los datos no serían coherentes para uno (si no se produce la segunda edición) ni para otro (si se sobrescriben los nuevos datos editados).        

Para solventar esta traba a la hora de actualizar una base de datos se pueden esgrimir dos recursos o modelos: la concurrencia pesimista y la concurrencia optimista. Los objetos que manipulan datos en los distintos lenguajes de programación están preparados para manejar ambas técnicas, por lo que no nos va a resultar nada complicado aplicar una u otra. Nosotros apostamos desde siempre por la concurrencia optimista, sobre todo en determinados entornos, pero explicaremos brevemente en que consisten los dos procedimientos.        

La concurrencia pesimista implica bloquear filas, o registros, en el origen de datos para impedir que otros usuarios modifiquen la información, de tal forma que el usuario actual resulte afectado. En un modelo pesimista, cuando un usuario realiza una acción que hace que se aplique un bloqueo, otros usuarios no pueden realizar acciones que entrarían en conflicto con ese bloqueo hasta que el propietario del mismo lo libere. Este modelo se utiliza principalmente en aquellos entornos en los que hay mucha contención de datos, de manera que el costo de protegerlos mediante bloqueos es menor que el costo de deshacer transacciones si se producen conflictos de concurrencia.        

La concurrencia pesimista puede resultar útil en ambientes donde los tiempos de bloqueo son cortos, por ejemplo la actualización automática de registros, según determinadas reglas, mediante software. Sin embargo, es una técnica que consume recursos del servidor, necesita de una conexión persistente con el gestor de datos y no resulta nada escalable cuando los usuarios, interactuando con los datos, hacen que los registros queden bloqueados durante períodos de tiempo relativamente largos (mientras se modifican las líneas de una factura, por ejemplo).        

Por el contrario, utilizando el sistema de concurrencia optimista no se bloquean filas cuando se lee, sino que se realizan copias locales desconectadas de los datos y, una vez se hayan editado, se vuelca la nueva información sobre la base de datos original. En este caso se produce el problema al que aludíamos al principio, ya que en el tiempo que nosotros hemos estado modificando los datos, otro usuario ha podido acceder al registro y haber realizado sus propias modificaciones. Es, entonces, la aplicación informática la que debe determinar si la información se han modificado o no desde que se leyó. Esta técnica, aunque parezca más farragosa de implementar, mejora el rendimiento del sistema y la velocidad de acceso de todos usuarios, ya que el origen de datos no se encuentra nunca bloqueado y puede servir información continuamente y bajo demanda.        

En el momento en que un equipo intente modificar determinados registros y detecte que han sido ya modificados con respecto a la información original que tenía desde que se leyó, en el modelo de concurrencia optimista se considera que hay una infracción. La pericia del programador consistirá en detectar dichas infracciones y saber actuar a tal efecto, dependiendo del proceso que se esté realizando y de las circunstancias puntuales. Esto es, una infracción puede resolverse sobrescribiendo los nuevos datos o manteniendo las modificaciones sin realizar. En función de las características del proyecto y de las necesidades del cliente habrá que hacer una u otra cosa.        

Vamos a ver un ejemplo práctico haciendo uso de una pequeña tabla de tres campos y un único registro. La tabla original podría ser como la siguiente:  

IdCliente  Apellido  Nombre
101  Martínez  Cris 

Imaginemos que un Usuario_1 lee la fila anterior de la base de datos a las 12:00 AM. Veamos una representación gráfica de los tres valores que nos ocupan: el valor original (valor cuando se leyó el registro), el valor actual (el que modifica Usuario_1 en local) y el valor en la base de datos (el valor que se encuentra registrado en la tabla). 

Nombre de columna Valor original Valor actual Valor en la base de datos  
IdCliente   101   101   101  
Apellido   Martínez   Martínez   Martínez  
Nombre   Cris   Cris   Cris  

En este caso los tres valores coinciden, porque Usuario_1 todavía no ha hecho ninguna modificación, simplemente ha extraído la información.        

A las 12:01 AM, un nuevo Usuario_2 recurre al servidor para leer la misma fila, y a las 12:03 AM edita el campo Nombre (cambia “Cris” por “Cristina”) y actualiza la base de datos. Nuestra representación visual del baile de cadenas de texto sería ahora la que sigue:  

Nombre de columna Valor original Valor actual Valor en la base de datos
IdCliente 101 101 101
Apellido Martínez Martínez Martínez
Nombre Cris Cristina Cris

La actualización se realiza correctamente porque los valores contenidos en la base da datos en el momento de renovar la fila coinciden con los valores originales de tenía Usuario_2 (“Cris”, en la base de datos, es igual que el dato “Cris” del momento de la lectura); no existe ninguna infracción para Usuario_2.        

Vamos a imaginar ahora que Usuario_1 termina de realizar sus modificaciones a las 12:05 AM (cambia “Cris”, su lectura, por “María Cristina”). Veamos la representación:

Nombre de columna Valor original Valor actual Valor en la base de datos
IdCliente 101 101 101
Apellido Martínez Martínez Martínez
Nombre Cris María Cristina Cristina

Al intentar actualizar se va a encontrar con una infracción de la concurrencia optimista, ya que el valor actual de la base de datos (“Cristina”) no coincide con el valor que él esperaba para ese campo (“Cris”) porque Usuario_2 lo había modificado previamente. Es ahora el momento en el que hay que tomar la decisión de sobrescribir los cambios realizados o, por el contrario, cancelar la actualización. Como antes decíamos, la elección de una u otra acción dependerá de la situación en concreto y de las querencias del cliente.        

Existen varias técnicas para determinar una infracción de concurrencia optimista a la hora de actualizar una base de datos. Una de ellas consiste en incluir una columna de marca de tiempo en la tabla. Las bases de datos suelen ofrecer funcionalidad de marca de tiempo que puede utilizarse para identificar la fecha y la hora en que se actualizó el registro por última vez. Mediante esta técnica, decimos, se incluye una columna de marca de tiempo en la definición de la tabla y, siempre que se actualiza el registro, se actualiza la marca de tiempo, de manera que queden reflejadas la fecha y la hora actuales. Al hacer una prueba para ver si hay infracciones de la concurrencia optimista, la columna de marca de tiempo se devuelve con cualquier consulta del contenido de la tabla. Cuando se intenta realizar una actualización, se compara el valor de marca de tiempo de la base de datos con el valor de marca de tiempo original contenido en la fila modificada. Si coinciden, se realiza la actualización y se edita la columna de marca de tiempo con la hora actual, con el objeto de reflejar la actualización. Si no coinciden, se ha producido una infracción de la concurrencia optimista.        

Otra técnica para probar si hay alguna infracción relacionada con la concurrencia optimista consiste en comprobar que todos los valores de columna originales de una fila siguen coincidiendo con los existentes en la base de datos.        

Veamos la siguiente consulta SQL contra una base de datos:        

       
SELECT Col1, Col2, Col3 FROM Tabla1  
UPDATE Table1 Set Col1 = @NuevoValorCol1,
              Set Col2 = @NuevoValorCol2,
              Set Col3 = @NuevoValorCol3
WHERE Col1 = @ViejoValorCol1 AND
      Col2 = @ViejoValorCol2 AND
      Col3 = @ViejoValorCol3   
        

Lo que se hace es seleccionar (SELECT) los campos, o columnas, que se van a modificar para, después, actualizar (UPDATE), con los nuevos valores (@NuevoValorColX), todos aquellos donde (WHERE) los valores originales (@ViejoValorColX) coincidan con los valores actuales en base de datos (ColX).        

La teoría es sencilla, pero la implementación puede llegar a complicarse bastante, no por la técnica en sí, sino por la obligación de tomar una decisión en cada uno de los momentos. Será ya la intuición del desarrollador la que indique qué solución tomar en cada caso de infracción. Lo que sí debe quedar claro es que, excepto en determinadas y muy puntuales ocasiones, la concurrencia optimista siempre debe preferirse por encima de la pesimista. Es mejor resolver mal una infracción (cosa que puede corregirse a posteriori) que mantener una red de datos a un 40% de su capacidad total de gestión por acciones de bloqueo tras bloqueo, lentitud, falta de escalabilidad y desidia del usuario que es incapaz de trabajar en esas condiciones.

Web con acceso a datos sólo con Javascript y un TXT

Javascript + TXT

Javascript + TXT

En contra de lo que piensa el común de los mortales, es posible disponer de un sitio web con acceso a datos sin necesidad de utilizar ni una sola base de datos y ni una sola línea de código PHP o ASP. Es muy común descubrir foros de noticias donde los novatos preguntan cómo pueden acceder a una serie de datos almacenados sin necesidad de crear una web con código del lado del servidor, generando un acceso desde el propio navegador del lado del cliente. Y también es muy común encontrar las respuestas de “los entendidos” comentando que eso es imposible y que, si lo fuera, sería muy peligroso.  

Bueno, pues peligroso no sé, pero posible sí que es, y también muy sencillo. Sólo necesitamos un archivo de texto plano y unas cuantas sentencias en Javascript. ¿Empezamos?  

Si precisamos tener una web que almacene una gran cantidad de datos, como usuarios y contraseñas, artículos de una tienda, documentos o información de clientes y proveedores, se intuye necesario el camino más largo, esto es, un sitio con código de acceso a datos del lado del servidor (ASP, PHP…) y un gestor de bases de datos al uso (SQL Server, MySQL…). Sin embargo, en muchas ocasiones solamente es necesario mantener unos pocos datos que se actualizan a mano cada cierto tiempo, por ejemplo un listado de licitaciones abiertas de un ayuntamiento o una serie de ofertas de trabajo de una empresa.  

Cualquiera puede pensar que, en alguno de esos casos, la opción menos costosa sería la de modificar manualmente los archivos HTML cuando proceda y listo. Sin embargo, si la persona que tiene que realizar dichas modificaciones no es experta en diseño web (la secretaria del ayuntamiento, con respecto al ejemplo de las licitaciones, o la de la empresa, en el supuesto de las ofertas de trabajo) es más que probable que no sepa editar los documentos o que, si lo hace, los estropee para los restos.  

Para estas situaciones, o similares, existe un pequeño truco del que podemos hacer uso. El sistema consiste en pasar datos a un HTML como si de variables Javascript se tratara, enlazándolas desde un TXT externo. Veamos primero el archivo de texto y el HTML con Javascript para, después, pasar a comentarlos.  

  
Registro1="Administrador de sistemas";
Registro2="Programador en Java";
Registro3="Content Manager";
Registro4="Técnico Help Desk";
Enlace="empresa.html";
  
  
<html>

 <head>

  <script src="datos.txt"></script>

  <script type="text/javascript">
   function cargarDatos(){
    document.getElementById("Campo1").innerText=Registro1;
    document.getElementById("Campo2").innerText=Registro2;
    document.getElementById("Campo3").innerText=Registro3;
    document.getElementById("Campo4").innerText=Registro4;

    document.getElementById("CampoEnlace").href=Enlace;
   }
  </script>

 </head>

 <body onload="cargarDatos()">

  <table>
   <tr>
    <td colspan="3" id="Campo1"></td>
   </tr>

   <tr>
    <td id="Campo2"></td>
   </tr>

   <tr>
    <td id="Campo3"></td>
   </tr>

   <tr>
    <td id="Campo4"></td>
   </tr>
  </table>

  <br />
  <a id="CampoEnlace">Volver a la página anterior</a>

 </body>

</html>
  
Como podemos observar, el archivo de texto es muy sencillo, ya que sólo guarda una serie de constantes (Registro1, Registro2, Registro3, Registro4 y Enlace) con un valor alfanumérico asignado. Estas constantes las importamos desde el HTML como si de un archivo fuente de Javascript se tratase, concretamente en la línea <script src="datos.txt"></script>. De esta manera, el navegador adquiere el código externo para ser utilizado en la página actual, sólo que en este caso el código se compone exclusivamente de constantes y datos.  

Posteriormente se genera una función cargarDatos() (se inicia en el body onload) que lo que hace es asignar la información importada a cada etiqueta HTML identificada por su id, mediante la función document.getElementById. Hay que tener en cuenta el tipo de etiqueta que se quiere rellenar y sus peculiaridades particulares. Así pues, en el caso de los <td> (celdas regulares) se utiliza la propiedad innerText, y en el <a> (hipervínculo) se usa href para referirse al atributo que permite especificar el destino del enlace.  

Como vemos, es una técnica muy sencilla y altamente rentable, pues para pequeños conjuntos de información no sería necesario contratar alojamientos web de altas prestaciones en cuanto a acceso a datos se refiere. Además, lo único que debería aprender a manejar la persona al cargo es un software de FTP para poder subir el archivo TXT modificado cuando fuera necesario.  

Por supuesto que es un ejemplo muy sencillo, pero se puede complicar hasta el infinito. Imaginemos que deseamos ir añadiendo filas a la tabla dependiendo del número de registros, algo muy lógico; no siempre tienen por qué ser cuatro. El siguiente archivo de texto muestra un ejemplo de este caso.  

  
Registros=2;

Fecha1="11 de mayo de 2010";
Texto1="Contrato para el servicio de recepción y conserjería.";

Fecha2="11 de mayo de 2010";
Texto2="Contrato para el servicio de limpieza y mantenimiento.";
  
Veamos ahora cómo quedaría el código Javascript donde se define la función cargarDatos() en nuestro HTML.  

  
<script type="text/javascript">
 function cargarDatos(){
  var Elemento1;
  var Elemento2;

  for (i=1;i<=Registros;i++)
  {
   Elemento1="Fecha"+i;
   Elemento2="Texto"+i;
   document.getElementById(Elemento1).innerText=eval(Elemento1);
   document.getElementById(Elemento2).innerText=eval(Elemento2);
  }
 }
</script>
  
Podemos observar que ha cambiado sustancialmente. Ahora necesitamos un bucle (for) que recorra todos registros (variable Registros en el TXT) de uno en uno y vaya asignando valores a las etiquetas. En este caso hacemos uso de dos variables (Elemento1 y Elemento2) que nos sirven para generar los nombres de las etiquetas HTML para después pasárselas a la función getElementById. Además, por simplificar, hemos utilizado el mismo nombre de las etiquetas HTML para las constantes y deberemos evaluarlas con la función eval antes de asignarlas, porque si no Javascript no se entera al ser una cadena creada a mano mediante la concatenación de un texto y el valor del contador i.  

A continuación vemos el código Javascript para dibujar la tabla dependiendo del número de registros.  

  
<script type="text/javascript">
 document.write("<table>");
 for (i=1;i<=Registros;i++)
 { 
  document.write("<tr>");
  document.write("<td id='Fecha"+i+"'></td>");
  document.write("</tr>");

  document.write("<tr>");
  document.write("<td id='Texto"+i+"'></td>");
  document.write("</tr>");

  document.write("<tr><td>&nbsp;</td></tr>");
 }
 document.write("</table>");
</script>
  
Lo que hacemos simplemente es recorrer todos los registros e ir añadiendo filas y celdas con sus correspondientes etiquetas id. Al final de cada bucle se agrega una celda vacía (con un espacio) para separar un poco cada grupo.  

Evidentemente, el usuario deberá actualizar manualmente, además de los registros propiamente dichos, la constante que define el total de registros para que funcione todo bien. También habrá de preocuparse por escribir correlativamente los nombres de las constantes y no cometer ningún otro error en la generación del archivo.  

Lo que habíamos dicho al principio, si es un número reducido de registros de datos, y estos no se actualizan frecuentemente, nos puede ser de mucha utilidad el uso de esta técnica (hay que tener en cuenta que cada variable o constante es un espacio en memoria que ocupa sitio); para soluciones más complejas se nos queda corta. ¡Hala, a programar se ha dicho!

Frases con historia (VI)

La verdad es que ninguna base de datos online sustituirá a tu periódico diario, ningún CD-ROM puede reemplazar a un profesor competente y ninguna red de ordenadores cambiará el modo de trabajar del Gobierno.

Clifford Stoll, Físico y Astrónomo estadounidense. 1995.

Sigue teknoPLOF! vía…
 
Twitter
RSS
 
Publicidad