Alan Daniel Lavintman Arquitecto de Software alavintman@mobilecomputing.com.ar n todo proyecto de software, el manejo de la persisten- cia normalmente representa una inversin de esfuerzo muy grande, que se traduce en un costo ms elevado para nuestra aplicacin. En la actualidad, para resol- ver esta problemtica, se utilizan herramientas de mapeo objeto-re- lacional, tales como Hibernate, que nos ofrecen una solucin que dista de ser ptima cuando se trata de implementar un software es- pecfico, tal como software en tiempo real o software embebido (por ejemplo, en PDA) o aquel que se instala en algn contexto cerrado donde se requiere una base de datos transparente. La librera db4objects fue diseada para proveer un motor embe- bido de base de datos orientado a objetos para dispositivos mvi- les, desktops o servidores donde se requiera alto desempeo, sincro- nizacin, consumo mnimo de recursos y, principalmente, cero ad- ministracin. Se trata de una librera de cdigo abierto (con licen- cia GPL y tambin comercial) que podemos integrar a nuestros pro- yectos muy fcilmente. Es nativa a los entornos donde opera (po- see versiones Java, .NET y Mono), y permite realizar transacciones confiables y escalables con tan slo una lnea de cdigo, sin impor- tar lo compleja que sea la estructura de los objetos por almacenar. A diferencia de los sistemas relacionales y de las bases de objetos no nativas, db4o almacena los objetos directamente, sin realizar ningn tipo de conversin. Los usuarios buscan, en la prctica, ciertas caractersticas desea- bles en un motor de base de datos de este tipo: que sea pequeo, rpido, poderoso y fcil de utilizar. Esto se traduce en requerimien- tos de consumo de recursos mnimos (importante para dispositivos embebidos), alta velocidad de procesamiento, instalacin y uso sen- cillos (con curva de aprendizaje pequea y un corto tiempo para sentirse cmodo con la base de datos), portabilidad (no ligada a un sistema operativo especfico) y confiabilidad. Veamos ahora en detalle cada uno de estos requisitos: >Consumo mnimo de recursos: A pesar de que los avances en tecnologa permiten a los diseadores de sistemas comprar ms memoria a precios cada vez ms bajos, la optimizacin del con- sumo de memoria de una aplicacin nunca pasar de moda. El E db4o: una alternativa a la persistencia En este artculo presentaremos este motor embebido de base de datos orientado a objetos, y mostraremos ejemplos de su uso que permiten a los desarrolladores Java y .NET reducir los tiempos y costos de trabajo. users.code 50 German Viscuso Licenciado en Sistemas de Computacin germanviscuso@gmail.com ACID ACID es un acrnimo para cuatro caractersticas que una base de datos debe proveer para constituir un sistema utili- zable. Cada letra corresponde a: > Atomicidad: Los componentes de una transaccin en la base de datos deben ejecutar en un rgimen de todo o na- da. Por ejemplo, si una transaccin en la base de datos consiste en eliminar cuatro objetos, entonces todos ellos deben ser borrados en una operacin atmica como si fue- ran uno. No es aceptable que tres de ellos sean eliminados y que, de alguna forma, el ltimo permanezca en la base. > Consistencia: Las operaciones sobre la base de datos la mueven de un estado bien definido al siguiente, sin esta- dos intermedios visibles. Por ejemplo, si el usuario agreg el objeto B a la base de datos, luego no debera ser posible que ese usuario (o cualquier otro) recuperara el objeto B de forma parcial. Para l, la base no debera nunca encon- trarse en un estado en el que las operaciones hayan sido completadas slo parcialmente. > Aislamiento (Isolation): Mltiples transacciones trabajan- do en la base de datos no se conocen entre s. Si dos usuarios intentan modificar el mismo objeto simultnea- mente, la base debe implementar algn mecanismo para serializar el acceso a l y evitar que se produzca interfe- rencia entre usuarios. > Durabilidad: Una vez que una transaccin se ha concreta- do en la base de datos, el trabajo no se pierde, incluso, an- te fallas de hardware y/o software. Si el usuario ejecuta una transaccin para eliminar tres objetos, y el sistema se cae mientras se est eliminando el segundo, luego, al rei- niciar, la base de datos se recuperar y terminar la tran- saccin incompleta. 50-54 code34 Architecture.qxd 1/17/07 2:15 PM Page 50 clculo es sencillo: si nuestro motor de base de datos consume menos memoria, habr ms disponible para otros componentes de la aplicacin, y el diseador podr agregar ms caractersti- cas (o incrementar el desempeo de las existentes). >Alto rendimiento: Este requerimiento est fuera de discusin. En muy pocas aplicaciones se toleran largos tiempos de acceso. Puesto de otra forma, no se conocen quejas de una base de da- tos que devuelva los resultados demasiado rpido. >Fcil implementacin: A pesar de los ltimos avances en la pro- gramacin, los desarrolladores an deben disear y codificar la lgica de negocio de la aplicacin, una tarea todava difcil. Por lo tanto, la API de un motor de base de datos debera poseer una curva de aprendizaje mnima y reducir el tiempo necesario para sentirse cmodo con el uso del motor. Adicionalmente, incorporar la funcionalidad de base de datos en un proyecto de desarrollo tendra que ser un proceso sencillo. Idealmente, la librera consistira en un solo archivo (para Java, un .JAR; para .NET, un archivo .DLL). Para proyectos basados en un IDE, el agregado debera ser una operacin de arrastrar y soltar. >Portabilidad: Un motor de base de datos debera ser multiplata- forma, para maximizar las ubicaciones donde puede correr y, as, incrementar los potenciales clientes de la aplicacin. Una amplia portabilidad les da a los desarrolladores el lujo de programar en un S.O. importante y, de este modo, tomar ventaja de las herra- mientas de desarrollo y debugging de ltima generacin, con la garanta de que el resultado no estar ligado a ese S.O. >Confiabilidad: Es otro requerimiento indiscutible y, quizs, el ms importante. Una base de datos no confiable es, simplemente, inu- tilizable. Para la mayora de las aplicaciones empotradas en espe- cial, las empleadas en sistemas de tiempo real, la confiabilidad es una propiedad no negociable que deben tener todos los componen- tes. Ms an, el motor de base de datos debe desempearse de acuerdo con criterios reconocidos de la industria. Especficamente, la librera debe implementar las propiedades ACID. La solucin: db4o El motor de base de objetos db40 permite cubrir (y exceder) los re- querimientos antes mencionados. Vemoslos punto por punto: >Consumo mnimo de recursos: db4o est diseado para ser em- bebido en clientes u otros componentes de software, de manera totalmente invisible para el usuario final. Es por eso que viene como una librera fcil de incorporar, con un tamao que ronda los 400 Kb. Como el motor corre en el mismo proceso de la apli- cacin, el usuario cuenta con control completo sobre la adminis- tracin de memoria, y puede realizar procesos de profiling y de- bugging del desempeo sobre todo el sistema. Si la aplicacin est corriendo, la base tambin lo est, sin excepcin. Y an ms importante, db4o es extremadamente flexible a la ho- ra de actualizar una base existente con un modelo de objetos que ha cambiado. Siempre asume que no hay un administrador de base de datos y, por lo tanto, permite a la aplicacin cambiar del modelo viejo al modelo nuevo de modo transparente. >Alto rendimiento: El rendimiento de db4o es equiparable al de los mejores sistemas de bases de datos tradicionales. Los bench- marks que se muestran a continuacin indican el desempeo de db4o comparado con el de una base de datos SQL corriendo en una mquina de escritorio: >Fcil implementacin: Slo hay que agregar la librera nica de db4o (.jar o .dll) al entorno de desarrollo, abrir el archivo de ba- se de datos y almacenar cualquier objeto (sin importar su com- plejidad) con una sola lnea de cdigo. Por ejemplo, en Java: public void guardar(Automovil auto){ ObjectContainer db = Db4o.openFile(auto.yap); db.set(auto); db.commit(); db.close(); } [Figura 1] Mapeo objeto-relacional vs. almacenamiento nativo de objetos. Benchmarking de db4o. La tabla muestra el desempeo de db4o comparado con el de una base de datos SQL de escritorio, para un conjunto de operaciones representativas de lectura (select) e insercin. En todo proyecto, el manejo de la persistencia normalmente representa una inversin de esfuerzo muy grande, que se traduce en un costo ms elevado para nuestra aplicacin. 51 RDBMS db4o db4o Test db4o SQL de escritorio Insert Complejo 1 48,25 Select Complejo 1 2,32 Insert de Enteros 1 27,74 Select de Enteros 1 0,7 Insert de Strings 1 20,26 Select de Strings 1 0,48 50-54 code34 Architecture.qxd 1/17/07 2:15 PM Page 51 users.code {architecture | db40} Esta facilidad de uso sin precedentes se traduce en una reduccin drstica de los tiempos de desarrollo. Se elimina efectivamente todo el trabajo de disear, implementar y mantener el esquema de base de datos, ya que el propio modelo de objetos conforma este esque- ma. Y ya no se necesita administrar tareas relacionadas con la base de datos, como strings, archivos XML u otros archivos no nativos. >Portabilidad: Pocas bases de datos embebibles corren de mane- ra nativa en tantas plataformas orientadas a objetos como db4o. sta permite desarrollar aplicaciones para desplegar en varias plataformas (por ejemplo, en PDAs) o en combinaciones hetero- gneas de clientes Windows y servidores Java. Este motor soporta desde el JDK 1.1.x de Java hasta el 5.0, y es soportado en Java EE y Java SE. Tambin corre con dialectos de J2ME que soportan reflexin, como CDC, PersonalProfile, Sava- Je y Zaurus (db4o tambin correr pronto en dialectos sin refle- xin, como CLDC, RIM/Blackberry y Palm OS). Tambin es compatible con todas las plataformas .NET, el Com- pact Framework y Mono; y soporta todos los lenguajes .NET ad- ministrados, como C#, VB.NET, ASP.NET, Boo y Managed C++. >Confiabilidad: Finalmente, db4o soporta todas las caractersticas ACID. Mltiples usuarios simultneos de una base db4o son efec- tivamente aislados, y sus operaciones son serializadas de forma transparente por la librera. Las transacciones se terminan con los mtodos commit() y rollback() de la clase ObjectContainer. Y en caso de que el sistema se caiga durante una actualizacin de la base de datos, cuando el ObjectContainer de db4o es rea- bierto, se completan de forma correcta todas las transacciones interrumpidas. La librera db4o A continuacin, haremos una breve introduccin a la librera y daremos un ejemplo con los tpicos ms comunes que solemos en- contrar en un modelo orientado a objetos. El ejemplo ser presen- tado utilizando el lenguaje Java, slo por comodidad; no creemos que ste sea un problema para que desarrolladores de otros lengua- jes puedan comprender el concepto. Antes de comenzar, debemos tener en cuenta qu herramientas descargar para este ejemplo: la librera de db4o para Java, actual- mente en la versin 5.5; y el ObjectManager, en versin 1.8 (ver links al final del artculo). La [Figura 3] muestra el modelo que utilizaremos en este caso. A pesar de ser muy sencillo, nos ser de utilidad, ya que slo haremos hincapi en los datos por persistir. El modelo intenta resolver un problema sobre la aplicacin de planes de ahorro. La clase Cliente representa el acreedor del producto y est asociada a un Plan de ahorro. Para administrar ciertas validaciones propias del dominio, se agrega una RelacionLaboral, que, sobre la base del sueldo bru- to, calcula el valor neto para evaluar si un cliente supera cierto um- bral y, as, dejarlo habilitado frente a la empresa para abonar mes a mes la cuota correspondiente. El resto del apartado lo dedicaremos al cdigo fuente bsico ne- cesario para persistir los objetos de este ejemplo. Crearemos un proyecto Java utilizando el editor Eclipse y agrega- remos las referencias a los archivos Jar correspondientes a la libre- ra db4o 5.5. La clase principal que nos brinda acceso a los servicios de db4o mediante sus mtodos estticos es la denominada ObjectContainer. El cdigo presentado en el Anexo 1 ser nuestro primer ejemplo, en el cual nos limitaremos a persistir los objetos de RelacionLaboral. Se trata de un proceso similar al almacenamiento de una tabla de tipos de en la modalidad relacional, aquellas que presentaban una rela- cin, por ejemplo, entre producto y tipo de producto, y esta ltima tabla sola ser un id-descripcion. Como se observa en el cdigo, po- demos persistir las entidades del modelo fcilmente a travs del Ob- jectContainer, con el mtodo set(). //Obtenemos una instancia de ObjectContainer ObjectContainer oc = Db4o.openFile(db.yap); //Construimos las Relaciones Autonomo autonomo = new Autonomo(800, 800); RelacionDependencia dependencia = new RelacionDependencia(1400); //Persistimos los objetos 52 Los usuarios buscan, en la prctica, ciertas caractersticas deseables en un motor de base de datos de este tipo: que sea pequeo, rpido, poderoso y fcil de utilizar. [Figura 3] Modelo de objetos utilizado en nuestro ejemplo. [Figura 2] Requisitos de una base de datos embebida. Base de datos embebida Cliente Cliente Cliente RelacionLaboral RelacionDependencia Plan Plan Plan Plan Autonomo 1 1..* 0..* 1 Bajo consumo de recursos Portabilidad Confiabilidad Fcil instalacin y uso Alto desempeo 50-54 code34 Architecture.qxd 1/17/07 2:15 PM Page 52 53 oc.set(autonomo); oc.set(dependencia); //Creamos un cliente. Para ello necesitaremos una relacin //laboral por lo tanto la buscaremos por ID autonomo = oc.ext().getByID(1927); Cliente cliente = new Cliente(autonomo); Cliente.setNombre(UsuarioDb4o); oc.set(cliente); oc.close(); Un punto importante para tener en cuenta es la insercin de du- plicados. Este tema es de inters, ya que suele confundir a algunas personas que recin comienzan a utilizar el producto. Cuando se guarda un objeto X compuesto por otros objetos Y, hay que consi- derar que estos ltimos deberan haberse persistido previamente (es- to se puede observar en el primer ejemplo de cdigo). Si la opera- cin no se realiza de esta forma, aunque el objeto Y dentro del ob- jeto X sea idntico a otro objeto Y ya persistido antes, db4o alma- cenar toda la estructura del objeto X, y as, dejar un duplicado de cada objeto Y. El hecho de salvar este inconveniente no constituye una tarea compleja y, a la hora de construir el objeto X, haremos una consulta a db4o para obtener el objeto Y, y utilizaremos esta re- ferencia para trabajar; una vez obtenida de la base, ya es tomada en cuenta por db4o en las operaciones siguientes con el objeto. En el primer extracto de cdigo vemos cmo buscar un objeto Autonomo por su identificador. Este tratamiento de identificadores est manejado totalmente por db4o a travs de una extensin del ObjectContainer accesible por el mtodo ext(). Por lo tanto, no ne- cesitaremos agregar informacin extra a nuestras clases (una cua- lidad que resulta menos intrusiva). En la segunda parte de cdigo mostramos los ejemplos de consul- tas; db4o presenta tres mtodos para realizar consultas. El primer mtodo es Query By Example (QBE), en el cual la idea principal es darle al ObjectContainer un objeto que represente el criterio de bsqueda de los objetos, para que nos d resultados de objetos con las caractersticas del objeto otorgado (se utiliza un prototipo de bsqueda). El segundo mtodo se denomina SODA (Simple Object Database Access), y con l podremos realizar las consultas ms complejas dentro de estructuras profundas a travs de la clase Query. Esta cla- se provee mtodos particulares que nos permiten descender en la informacin de las propiedades de los objetos por buscar. Por ltimo, el mtodo ms apreciado por los fanticos es el de las consultas nativas (Native Queries), en el que la consulta se realiza en el propio lenguaje de programacin del ambiente en que este- mos desarrollando. Por lo tanto, son 100% seguras a nivel de tipos, 100% verificadas en tiempo de compilacin y, por supuesto, 100% refactorizables. En el ejemplo incluimos las tres formas de consulta de objetos con db4o para obtener nuestro ObjectSet con los objetos resultado. Sin embargo, vamos a hacer una consideracin especial a las consultas nativas, ya que estn marcando una tendencia y han causado una re- volucin en la forma en que se consulta una base de datos. El com- portamiento principal que hay que tener en cuenta con este tipo de consultas es el de desempeo. Las consultas nativas funcionan sobre SODA, por lo que cada una de ellas pasa por un conversor, lo cual implica un tiempo de procesador, y la ejecucin se hace en formato SODA. Para mejorar estos tiempos, db4o pens en una herramienta llamada Native Query Optimizer, que se encarga de configurar el con- tenedor para que las consultas sean ptimas. //Obtenemos una instancia de ObjectContainer ObjectContainer oc = Db4o.openFile(db.yap); //Realizamos una consulta por QBE Cliente cliente = new Cliente(UsuarioDb4o); ObjectSet<Cliente> clientes = oc.get(cliente); ImprimirClientes(clientes); //Realizamos una consulta por SODA Query query = oc.query(); query.constrain(Cliente.class); query.descend(nombre).constrain(UsuarioDb4o); ObjectSet<Cliente> clientes = query.execute(); ImprimirClientes(clientes); //Realizamos una consulta por Native Queries List<Cliente> clientes = oc.query(new Predicate<Cliente>(){ public boolean match(Cliente client){ return client.getNombre().equals(UsuarioDb4o); Se elimina efectivamente todo el trabajo de disear, implementar y mantener el esquema de base de datos, ya que el propio modelo de objetos conforma este esquema. El mtodo ms apreciado por los fanticos es el de las consultas nativas (Native Queries), en el cual la consulta se realiza en el propio lenguaje de programacin. Por lo tanto, son 100% seguras a nivel de tipos, 100% verificadas en tiempo de compilacin y, por supuesto, 100% refactorizables. [Figura 4] Los tres mtodos para realizar consultas en db4o. Consultas Consulta con ejemplos SODA Consulta nativa 50-54 code34 Architecture.qxd 1/17/07 2:15 PM Page 53 54 users.code {architecture | reportes} } }); ImprimirClientes(clientes); oc.close(); Hasta aqu, podemos notar que la librera se comporta como debe- ra, pero nos queda una sensacin de vaco al no saber dnde estn realmente los objetos. Para visualizarlos, podremos utilizar la herra- mienta ObjectBrowser. Una vez ejecutada esta aplicacin, abrimos el archivo de la base utilizando File/Open File, apuntamos al archivo y veremos algo semejante a lo que se muestra en la [Figura 5]. Las particularidades que podemos observar aqu son el almacena- miento de la jerarqua, donde la clase abstracta es efectivamente al- macenada y guarda un puntero a los objetos concretos; y la admi- nistracin de los identificadores por parte del ObjectContainer. Otro tema importante para tener en cuenta es el incremento de de- sempeo a partir de la versin 5.4 (por lo que recomendamos usar una versin mayor o igual), en la que se introdujo una arquitectura de rboles B (BTrees) diseada para todos los ndices que posee db4o, tales como ndices de clase, de atributos y de colecciones. Conclusin La librera db4o es una solucin de persistencia ideal cuando se necesita una base transparente y fcil de utilizar, para incorpo- rar rpidamente en un proyecto Java o .NET sin sacrificar desem- peo. Logra acortar los tiempos de entrega de nuestras aplicacio- nes de forma significativa, ya que permite concentrarnos direc- tamente en el dominio del problema (nuestros objetos), sin que debamos invertir demasiado tiempo en la solucin de persisten- cia (mapeos objeto-relacionales, archivos XML, etc.). Adems, ofrece caractersticas avanzadas, como soporte transparente a cambios en las versiones de los objetos (evolucin del esquema), cero administracin (no requiere DBA) y consultas nativas. Y, por si esto fuera poco, es de cdigo abierto! Para los casos de uso en los que se requiera soporte a sistemas legacy, db4o cuenta con un sistema de replicacin (dRS), que permite replicar los datos a sis- temas relacionales y viceversa. Alan Lavintman comenz como a desempearse como desarrolla- dor hace seis aos y, actualmente, est trabajando para mobile computing dentro del rea de metodologa e investigacin. German Viscuso es Licenciado en Sistemas de Computacin. Co- menz su carrera como desarrollador freelance y, luego, incursion tambin en el rea comercial en informtica. G [Figura 6] El sistema de replicacin de db4o (dRS) permite replicar datos con sistemas relacionales de forma bidireccional. [Figura 5] El ObjectBrowser de db4o permite administrar los objetos almacenados en la base de datos. Referencias > www.db4o.com > www.db4o.com/espanol > developer.db4o.com RDBMS (Oracle) dRS (Hibernate) db4o db4o db4o db4o Application (Java/.NET) 50-54 code34 Architecture.qxd 1/17/07 2:15 PM Page 54