Zope Object Database ( ZODB ) es una base de datos orientada a objetos para almacenar de forma transparente y persistente objetos Python . Se incluye como parte del servidor de aplicaciones web Zope , pero también se puede utilizar de forma independiente de Zope.
Las características de ZODB incluyen: transacciones, historial/deshacer, almacenamiento conectable de forma transparente, almacenamiento en caché integrado, control de concurrencia de múltiples versiones (MVCC) y escalabilidad a través de una red (usando ZEO ).
La base de datos de objetos Zope (ZODB) fue creada por Jim Fulton de Zope Corporation a finales de los años 90. Inicialmente, comenzó como un simple sistema de objetos persistentes (POS) durante el desarrollo de Principia, que más tarde evolucionó hasta convertirse en Zope. Un cambio arquitectónico significativo llevó a cambiar el nombre del sistema a ZODB 3. Posteriormente, se presentó ZODB 4 como un proyecto de corta duración destinado a reimplementar todo el paquete ZODB 3 utilizando 100 % Python.
ZODB almacena objetos de Python utilizando una versión extendida de la persistencia de objetos incorporada de Python (pickle). Una base de datos ZODB tiene un único objeto raíz (normalmente un diccionario), que es el único objeto al que la base de datos puede acceder directamente. Se puede acceder a todos los demás objetos almacenados en la base de datos a través del objeto raíz. Los objetos a los que hace referencia un objeto almacenado en la base de datos también se almacenan automáticamente en la base de datos.
ZODB admite transacciones simultáneas mediante MVCC y realiza un seguimiento de los cambios en los objetos por objeto. Solo se confirman los objetos modificados. Las transacciones no son destructivas de manera predeterminada y se pueden revertir.
Por ejemplo, supongamos que tenemos un automóvil descrito mediante tres clases Car
, Wheel
y Screw
. En Python, esto podría representarse de la siguiente manera:
Clase Coche : [ ... ] Clase Rueda : [ ... ] Clase Tornillo : [ ... ]miCoche = Coche () miCoche . rueda1 = Rueda () miCoche . rueda2 = Rueda () para rueda en ( miCoche . rueda1 , miCoche . rueda2 ): rueda . tornillos = [ Tornillo (), Tornillo ()]
Si la variable mycar es la raíz de la persistencia, entonces:
zodb [ 'micoche' ] = miCoche
Esto almacena todas las instancias de objetos (automóvil, rueda, tornillos, etc.) para que puedan recuperarse más tarde. Si otro programa obtiene una conexión a la base de datos a través del objeto mycar, se ejecuta lo siguiente:
coche = zodb [ 'miCoche' ]
Y recupera todos los objetos, el puntero al coche se mantiene en la car
variable. Luego, en una etapa posterior, este objeto se puede modificar con un código Python como:
coche . rueda3 = Rueda () coche . rueda3 . tornillos = [ Tornillo ()]
El almacenamiento se modifica para reflejar el cambio de datos (después de que se ordena una confirmación).
No existe ninguna declaración de la estructura de datos ni en Python ni en ZODB, por lo que se pueden agregar libremente nuevos campos a cualquier objeto existente.
Para que se produzca la persistencia, la clase Car de Python debe derivarse de la Persistence.Persistent
clase; esta clase contiene los datos necesarios para que funcione la maquinaria de persistencia, como el identificador interno del objeto, el estado del objeto, etc., pero también define el límite de la persistencia en el siguiente sentido: cada objeto cuya clase deriva de Persistent es la unidad atómica de almacenamiento (el objeto completo se copia al almacenamiento cuando se modifica un campo).
En el ejemplo anterior, si Car
es la única clase que deriva de Persistent, cuando wheel3
se agrega a car, todos los objetos deben escribirse en el almacenamiento. Por el contrario, si Wheel
también deriva de Persistent, cuando carzz.wheel3 = Wheel
se ejecuta, se escribe un nuevo registro en el almacenamiento para almacenar el nuevo valor de Car
, pero se conservan los existentes Wheel
y el nuevo registro de Car
apunta al registro ya existente Wheel
dentro del almacenamiento.
La maquinaria de ZODB no persigue las modificaciones a través del gráfico de punteros. En el ejemplo anterior, carzz.wheel3 = something
es una modificación que la maquinaria de ZODB rastrea automáticamente, porque carzz
es de la clase (Persistente) Car
. La maquinaria de ZODB hace esto marcando el registro como dirty
. Sin embargo, si hay una lista, la maquinaria de ZODB no detecta ningún cambio dentro de la lista y el programador debe ayudar agregando manualmente carzz._p_changed = 1
, notificando a ZODB que el registro realmente cambió. Por lo tanto, hasta cierto punto, el programador debe estar al tanto del funcionamiento de la maquinaria de persistencia.
La unidad de almacenamiento (es decir, un objeto cuya clase deriva de Persistent) también es la unidad de atomicidad . En el ejemplo anterior, si Cars
es la única clase Persistent, un hilo modifica una Wheel (el Car
registro debe ser notificado) y otro hilo modifica otro Wheel
dentro de otra transacción, la segunda confirmación fallará. Si Wheel
también es Persistent, ambos Wheels
pueden ser modificados independientemente por dos hilos diferentes en dos transacciones diferentes.
La persistencia de la clase (escritura de la clase de un objeto en particular en el almacenamiento) se obtiene escribiendo una especie de nombre "completamente calificado" de la clase en cada registro del disco. En Python, el nombre de la clase implica la jerarquía del directorio en el que reside el archivo fuente de la clase. Una consecuencia es que el archivo fuente del objeto persistente no se puede mover. Si se hace, la maquinaria de ZODB no puede localizar la clase de un objeto al recuperarlo del almacenamiento, lo que da como resultado un objeto dañado.
Zope Enterprise Objects (ZEO) es una implementación de almacenamiento de ZODB que permite que varios procesos de cliente almacenen objetos en un único servidor ZEO. Esto facilita el escalamiento transparente.
Network Storage (también conocido como ZEO) permite que varios procesos Python carguen y almacenen instancias persistentes simultáneamente. File Storage permite que un único proceso Python interactúe con un archivo en el disco. RelStorage permite que el almacén de respaldo de persistencia sea un RDBMS . Directory Storage almacena cada dato persistente como un archivo separado en el sistema de archivos, similar a FSFS en Subversion . Demo Storage funciona como un backend en memoria para el almacén persistente. BDBStorage, ahora abandonado, usaba un backend Berkeley DB .
Zope Replication Services (ZRS) es un complemento comercial de conmutación por error , de código abierto desde mayo de 2013, que elimina el punto único de falla, brindando respaldo activo para escrituras y balanceo de carga para lecturas. ZeoRAID es una solución de código abierto que ofrece un servidor de red proxy que distribuye almacenamiento de objetos y recuperación entre una serie de servidores de red. RelStorage, al utilizar tecnologías RDBMS, elimina la necesidad de un servidor ZEO. NEO es una implementación de almacenamiento distribuido que brinda tolerancia a fallas y balanceo de carga.