4.3 Versions

While many subtransactions can be contained within a single regular transaction, it's also possible to contain many regular transactions within a long-running transaction, called a version in ZODB terminology. Inside a version, any number of transactions can be created and committed or rolled back, but the changes within a version are not made visible to other connections to the same ZODB.

Not all storages support versions, but you can test for versioning ability by calling supportsVersions() method of the DB instance, which returns true if the underlying storage supports versioning.

A version can be selected when creating the Connection instance using the DB.open([version]) method. The version argument must be a string that will be used as the name of the version.

vers_conn = db.open(version='Working version')

Transactions can then be committed and aborted using this versioned connection. Other connections that don't specify a version, or provide a different version name, will not see changes committed within the version named "Working version". To commit or abort a version, which will either make the changes visible to all clients or roll them back, call the DB.commitVersion() or DB.abortVersion() methods. XXX what are the source and dest arguments for?

The ZODB makes no attempt to reconcile changes between different versions. Instead, the first version which modifies an object will gain a lock on that object. Attempting to modify the object from a different version or from an unversioned connection will cause a ZODB.POSException.VersionLockError to be raised:

from ZODB.POSException import VersionLockError

try:
    get_transaction().commit()
except VersionLockError, (obj_id, version):
    print ('Cannot commit; object %s '
           'locked by version %s' % (obj_id, version))

The exception provides the ID of the locked object, and the name of the version having a lock on it.