Zope Object Database
The Zope Object Database is an object-oriented database for transparently and persistently storing Python objects. It is included as part of the Zope web application server, but can also be used independently of Zope.
Features of the ZODB include: transactions, history/undo, transparently pluggable storage, built-in caching, multiversion concurrency control, and scalability across a network.
History
The Zope Object Database was created by Jim Fulton of Zope Corporation in the late 1990s. Initially, it began as a simple Persistent Object System during the development of Principia, which later evolved into Zope. A significant architectural change led to the renaming of the system to ZODB 3. Subsequently, ZODB 4 was introduced as a short-lived project aimed at re-implementing the entire ZODB 3 package using 100% Python.Implementation
Basics
ZODB stores Python objects using an extended version of Python's built-in object persistence. A ZODB database has a single root object, which is the only object directly made accessible by the database. All other objects stored in the database are reached through the root object. Objects referenced by an object stored in the database are automatically stored in the database as well.ZODB supports concurrent transactions using MVCC and tracks changes to objects on a per-object basis. Only changed objects are committed. Transactions are non-destructive by default and can be reverted.
Example
For example, say we have a car described using 3 classesCar, Wheel and Screw. In Python, this could be represented the following way:class Car:
class Wheel:
class Screw:
myCar = Car
myCar.wheel1 = Wheel
myCar.wheel2 = Wheel
for wheel in :
wheel.screws =
If the variable mycar is the root of persistence, then:
zodb = myCar
This puts all of the object instances into storage, which can be retrieved later. If another program gets a connection to the database through the mycar object, performing:
car = zodb
And retrieves all the objects, the pointer to the car being held in the
car variable. Then at some later stage, this object can be altered with a Python code like:car.wheel3 = Wheel
car.wheel3.screws =
The storage is altered to reflect the change of data.
There is no declaration of the data structure in either Python or ZODB, so new fields can be freely added to any existing object.
Storage unit
For persistence to take place, the Python Car class must be derived from thePersistence.Persistent class — this class both holds the data necessary for the persistence machinery to work, such as the internal object id, state of the object, and so on, but also defines the boundary of the persistence in the following sense: every object whose class derives from Persistent is the atomic unit of storage.In the example above, if
Car is the only class deriving from Persistent, when wheel3 is added to car, all of the objects must be written to the storage. In contrast, if Wheel also derives from Persistent, then when carzz.wheel3 = Wheel is performed, a new record is written to the storage to hold the new value of the Car, but the existing Wheel are kept, and the new record for the Car points to the already existing Wheel record inside the storage.The ZODB machinery doesn't chase modification down through the graph of pointers. In the example above,
carzz.wheel3 = something is a modification automatically tracked down by the ZODB machinery, because carzz is of class Car. The ZODB machinery does this by marking the record as dirty. However, if there is a list, any change inside the list isn't noticed by the ZODB machinery, and the programmer must help by manually adding carzz._p_changed = 1, notifying ZODB that the record actually changed. Thus, to a certain extent the programmer must be aware of the working of the persistence machinery.Atomicity
The storage unit is also the atomicity unit. In the example above, ifCars is the only Persistent class, a thread modifies a Wheel, and another thread modifies another Wheel inside another transaction, the second commit will fail. If Wheel is also Persistent, both Wheels can be modified independently by two different threads in two different transactions.