[Checkins] SVN: zope2docs/trunk/ZODB added
Andreas Jung
andreas at andreas-jung.com
Sat Feb 21 03:16:10 EST 2009
Log message for revision 96862:
added
Changed:
A zope2docs/trunk/ZODB1.stx
A zope2docs/trunk/ZODB2.stx
-=-
Added: zope2docs/trunk/ZODB1.stx
===================================================================
--- zope2docs/trunk/ZODB1.stx (rev 0)
+++ zope2docs/trunk/ZODB1.stx 2009-02-21 08:16:10 UTC (rev 96862)
@@ -0,0 +1,395 @@
+ By Michel Pelletier
+
+ Introduction
+
+ In this article, we cover the very basics of the Zope Object
+ Database (ZODB) for Python programmers. This short article
+ documents almost everything you need to know about using this
+ powerful object database in Python. In a later article, I will
+ cover some of the more advanced features of ZODB for Python
+ programmers.
+
+ ZODB is a database for Python objects that comes with
+ "Zope":http://www.zope.org. If you've ever worked with a
+ relational database, like PostgreSQL, MySQL, or Oracle, than you
+ should be familiar with the role of a database. It's a long term
+ or short term storage for your application data.
+
+ For many tasks, relational databases are clearly a good solution,
+ but sometimes relational databases don't fit well with your object
+ model. If you have lots of different kinds of interconnected
+ objects with complex relationships, and changing schemas then ZODB
+ might be worth giving a try.
+
+ A major feature of ZODB is transparency. You do not need to write
+ any code to explicitly read or write your objects to or from a
+ database. You just put your *persistent* objects into a container
+ that works just like a Python dictionary. Everything inside this
+ dictionary is saved in the database. This dictionary is said to
+ be the "root" of the database. It's like a magic bag; any Python
+ object that you put inside it becomes persistent.
+
+ Actually there are a few restrictions on what you can store in the
+ ZODB. You can store any objects that can be "pickled" into a
+ standard, cross-platform serial format. Objects like lists,
+ dictionaries, and numbers can be pickled. Objects like files,
+ sockets, and Python code objects, cannot be stored in the database
+ because they cannot be pickled. For more information on
+ "pickling", see the Python pickle module documentation at
+ http://www.python.org/doc/current/lib/module-pickle.html
+
+ A Simple Example
+
+ The first thing you need to do to start working with ZODB is to
+ create a "root object". This process involves first opening a
+ connection to a "storage", which is the actual back-end that stores
+ your data.
+
+ ZODB supports many pluggable storage back-ends, but for the
+ purposes of this article I'm going to show you how to use the
+ 'FileStorage' back-end storage, which stores your object data in a
+ file. Other storages include storing objects in relational
+ databases, Berkeley databases, and a client to server storage that
+ stores objects on a remote storage server.
+
+ To set up a ZODB, you must first install it. ZODB comes with
+ Zope, so the easiest way to install ZODB is to install Zope and
+ use the ZODB that comes with your Zope installation. For those of
+ you who don't want all of Zope, but just ZODB, see the
+ instructions for downloading StandaloneZODB from the "ZODB web
+ page":http://www.zope.org/Wikis/ZODB/FrontPage
+
+ StandaloneZODB can be installed into your system's Python
+ libraries using the standard 'distutils' Python module.
+
+ After installing ZODB, you can start to experiment with it right
+ from the Python command line interpreter. For example, try the
+ following python code in your interpreter::
+
+ >>> from ZODB import FileStorage, DB
+ >>> storage = FileStorage.FileStorage('mydatabase.fs')
+ >>> db = DB(storage)
+ >>> connection = db.open()
+ >>> root = connection.root()
+
+ Here, you create storage and use the 'mydatabse.fs' file to store
+ the object information. Then, you create a database that uses
+ that storage.
+
+ Next, the database needs to be "opened" by calling the 'open()'
+ method. This will return a connection object to the database.
+ The connection object then gives you access to the 'root' of the
+ database with the 'root()' method.
+
+ The 'root' object is the dictionary that holds all of your
+ persistent objects. For example, you can store a simple list of
+ strings in the root object::
+
+ >>> root['employees'] = ['Mary', 'Jo', 'Bob']
+
+ Now, you have changed the persistent database by adding a new
+ object, but this change is so far only temporary. In order to
+ make the change permanent, you must commit the current
+ transaction::
+
+ >>> get_transaction().commit()
+
+ Transactions group of lots of changes in one atomic operation. In
+ a later article, I'll show you how this is a very powerful
+ feature. For now, you can think of committing transactions as
+ "checkpoints" where you save the changes you've made to your
+ objects so far. Later on, I'll show you how to abort those
+ changes, and how to undo them after they are committed.
+
+ Now let's find out if our data was actually saved. First close the
+ database connection::
+
+ >>> connection.close()
+
+ Then quit Python. Now start the Python interpreter up again, and
+ connect to the database you just created::
+
+ >>> from ZODB import FileStorage, DB
+ >>> storage = FileStorage.FileStorage('mydatabase.fs')
+ >>> db = DB(storage)
+ >>> connection = db.open()
+ >>> root = connection.root()
+
+ Now, let's see what's in the root::
+
+ >>> root.items()
+ [('employees', ['Mary', 'Jo', 'Bob'])]
+
+ There's your list. If you had used a relational database, you
+ would have had to issue a SQL query to save even a simple Python
+ list like the above example. You would have also needed some code
+ to convert a SQL query back into the list when you wanted to use
+ it again. You don't have to do any of this work when using ZODB.
+ Using ZODB is almost completely transparent, in fact, ZODB based
+ programs often look suspiciously simple!
+
+ Keep in mind that ZODB's persistent dictionary is just the tip of
+ the persistent iceberg. Persistent objects can have attributes
+ that are themselves persistent. In other words, even though you
+ may have only one or two "top level" persistent objects as values
+ in the persistent dictionary, you can still have thousands of
+ sub-objects below them. This is, in fact, how Zope does it. In
+ Zope, there is only *one* top level object that is the root
+ "application" object for all other objects in Zope.
+
+ Detecting Changes
+
+ One thing that makes ZODB so easy to use is that it doesn't
+ require you to keep track of your changes. All you have to do is
+ to make changes to persistent objects and then commit a
+ transaction. Anything that has changed will be stored in the
+ database.
+
+ There is one exception to this rule when it comes to simple
+ mutable Python types like lists and dictionaries. If you change a
+ list or dictionary that is already stored in the database, then
+ the change will *not* take effect. Consider this example::
+
+ >>> root['employees'].append('Bill')
+ >>> get_transaction().commit()
+
+ You would expect this to work, but it doesn't. The reason for
+ this is that ZODB cannot detect that the 'employees' list
+ changed. The 'employees' list is a mutable object that does not
+ notify ZODB when it changes.
+
+ There are a couple of very simple ways around this problem. The
+ simplest is to re-assign the changed object::
+
+ >>> employees = root['employees']
+ >>> employees.append('Bill')
+ >>> root['employees'] = employees
+ >>> get_transaction().commit()
+
+ Here, you move the employees list to a local variable, change the
+ list, and then *reassign* the list back into the database and
+ commit the transaction. This reassignment notifies the database
+ that the list changed and needs to be saved to the database.
+
+ Later in this article, we'll show you another technique for
+ notifying the ZODB that your objects have changed. Also, in a
+ later article, we'll show you how to use simple, ZODB-aware list
+ and dictionary classes that come pre-packaged with ZODB for your
+ convenience.
+
+ Persistent Classes
+
+ The easiest way to create mutable objects that notify the ZODB of
+ changes is to create a persistent class. Persistent classes let
+ you store your own kinds of objects in the database. For example,
+ consider a class that represents a employee::
+
+ import ZODB
+ from Persistence import Persistent
+
+ class Employee(Persistent):
+
+ def setName(self, name):
+ self.name = name
+
+ To create a persistent class, simply subclass from
+ 'Persistent.Persistent'. Because of some special magic that ZODB
+ does, you must first import ZODB before you can import Persistent.
+ The 'Persistent' module is actually *created* when you import
+ 'ZODB'.
+
+ Now, you can put Employee objects in your database::
+
+ >>> employees=[]
+ >>> for name in ['Mary', 'Joe', 'Bob']:
+ ... employee = Employee()
+ ... employee.setName(name)
+ ... employees.append(employee)
+ >>> root['employees']=employees
+ >>> get_transaction().commit()
+
+ Don't forget to call 'commit()', so that the changes you have made
+ so far are committed to the database, and a new transaction is
+ begun.
+
+ Now you can change your employees and they will be saved in the
+ database. For example you can change Bob's name to "Robert"::
+
+ >>> bob=root['employees'][2]
+ >>> bob.setName('Robert')
+ >>> get_transaction().commit()
+
+ You can even change attributes of persistent instaces without
+ calling methods::
+
+ >>> bob=root['employees'][2]
+ >>> bob._coffee_prefs=('Cream', 'Sugar')
+ >>> get_transaction().commit()
+
+ It doesn't matter whether you change an attribute directly, or
+ whether it's changed by a method. As you can tell, all of the
+ normal Python language rules still work as you'd expect.
+
+ Mutable Attributes
+
+ Earlier you saw how ZODB can't detect changes to normal mutable
+ objects like Python lists. This issue still affects you when using
+ persistent instances. This is because persistent instances can
+ have attributes which are normal mutable objects. For example,
+ consider this class::
+
+ class Employee(Persistent):
+
+ def __init__(self):
+ self.tasks = []
+
+ def setName(self, name):
+ self.name = name
+
+ def addTask(self, task):
+ self.task.append(task)
+
+ When you call 'addTask', the ZODB won't know that the mutable
+ attribute 'self.tasks' has changed. As you saw earlier, you can
+ reassign 'self.tasks' after you change it to get around this
+ problem. However, when you're using persistent instances, you have
+ another choice. You can signal the ZODB that your instance has
+ changed with the '_p_changed' attribute::
+
+ class Employee(Persistent):
+ ...
+
+ def addTask(self, task):
+ self.task.append(task)
+ self._p_changed = 1
+
+ To signal that this object has change, set the '_p_changed'
+ attribute to 1. You only need to signal ZODB once, even if you
+ change many mutable attributes.
+
+ The '_p_changed' flag leads us to one of the few rules of you must
+ follow when creating persistent classes: your instances *cannot*
+ have attributes that begin with '_p_', those names are reserved
+ for use by the ZODB.
+
+ A Complete Example
+
+ Here's a complete example program. It builds on the employee
+ examples used so far::
+
+ from ZODB import DB
+ from ZODB.FileStorage import FileStorage
+ from ZODB.PersistentMapping import PersistentMapping
+ from Persistence import Persistent
+
+ class Employee(Persistent):
+ """An employee"""
+
+ def __init__(self, name, manager=None):
+ self.name=name
+ self.manager=manager
+
+ # setup the database
+ storage=FileStorage("employees.fs")
+ db=DB(storage)
+ connection=db.open()
+ root=connection.root()
+
+ # get the employees mapping, creating an empty mapping if
+ # necessary
+ if not root.has_key("employees"):
+ root["employees"] = {}
+ employees=root["employees"]
+
+
+ def listEmployees():
+ if len(employees.values())==0:
+ print "There are no employees."
+ print
+ return
+ for employee in employees.values():
+ print "Name: %s" % employee.name
+ if employee.manager is not None:
+ print "Manager's name: %s" % employee.manager.name
+ print
+
+ def addEmployee(name, manager_name=None):
+ if employees.has_key(name):
+ print "There is already an employee with this name."
+ return
+ if manager_name:
+ try:
+ manager=employees[manager_name]
+ except KeyError:
+ print
+ print "No such manager"
+ print
+ return
+ employees[name]=Employee(name, manager)
+ else:
+ employees[name]=Employee(name)
+
+ root['employees'] = employees # reassign to change
+ get_transaction().commit()
+ print "Employee %s added." % name
+ print
+
+
+ if __name__=="__main__":
+ while 1:
+ choice=raw_input("Press 'L' to list employees, 'A' to add"
+ "an employee, or 'Q' to quit:")
+ choice=choice.lower()
+ if choice=="l":
+ listEmployees()
+ elif choice=="a":
+ name=raw_input("Employee name:")
+ manager_name=raw_input("Manager name:")
+ addEmployee(name, manager_name)
+ elif choice=="q":
+ break
+
+ # close database
+ connection.close()
+
+ This program demonstrates a couple interesting things. First, this
+ program shows how persistent objects can refer to each other. The
+ 'self.manger' attribute of 'Employee' instances can refer to other
+ 'Employee' instances. Unlike a relational database, there is no
+ need to use indirection such as object ids when referring from one
+ persistent object to another. You can just use normal Python
+ references. In fact, you can even use circular references.
+
+ A final trick used by this program is to look for a persistent
+ object and create it if it is not present. This allows you to just
+ run this program without having to run a setup script to build the
+ database first. If there is not database present, the program will
+ create one and initialize it.
+
+ Conclusion
+
+ ZODB is a very simple, transparent object database for Python that
+ is a freely available component of the Zope application server.
+ As these examples illustrate, only a few lines of code are needed
+ to start storing Python objects in ZODB, with no need to write SQL
+ queries. In the next article on ZODB, we'll show you some more
+ advanced techniques for using ZODB, like using ZODB's distributed
+ object protocol to distribute your persistent objects across many
+ machines.
+
+ ZODB Resources
+
+ Andrew Kuchling's "ZODB pages":http://www.amk.ca/zodb/
+
+ Zope.org "ZODB Wiki":http://www.zope.org/Wikis/ZODB/FrontPage
+
+ Jim Fulton's "Introduction to the Zope Object
+ Database":http://www.python.org/workshops/2000-01/proceedings/papers/fulton/zodb3.html
+
+
+
+
+
+
+
+
Added: zope2docs/trunk/ZODB2.stx
===================================================================
--- zope2docs/trunk/ZODB2.stx (rev 0)
+++ zope2docs/trunk/ZODB2.stx 2009-02-21 08:16:10 UTC (rev 96862)
@@ -0,0 +1,368 @@
+Advanced ZODB for Python Programmers
+
+ In the first article in this series, "ZODB for Python
+ Programmers":ZODB1 I covered some of the simpler aspects of Python
+ object persistence. In this article, I'll go over some of the more
+ advanced features of ZODB.
+
+ In addition to simple persistence, ZODB offers some very useful
+ extras for the advanced Python application. Specificly, we'll cover
+ the following advanced features in this article:
+
+ Persistent-Aware Types -- ZODB comes with some special,
+ "persistent-aware" data types for storing data in a ZODB. The
+ most useful of these is the "BTree", which is a fast, efficient
+ storage object for lots of data.
+
+ Voalitile Data -- Not all your data is meant to be stored in the
+ database, ZODB let's you have volatile data on your objects that
+ does not get saved.
+
+ Pluggable Storages -- ZODB offers you the ability to use many
+ different storage back-ends to store your object data, including
+ files, relational databases and a special client-server storage
+ that stores objects on a remote server.
+
+ Conflict Resolution -- When many threads try to write to the same
+ object at the same time, you can get conflicts. ZODB offers a
+ conflict resolution protocol that allows you to mitigate most
+ conflicting writes to your data.
+
+ Transactions -- When you want your changes to be "all or nothing"
+ transactions come to the rescue.
+
+ Persistent-Aware Types
+
+ You can also get around the mutable attribute problem discussed in
+ the first article by using special types that are "persistent
+ aware". ZODB comes with the following persistent aware mutable
+ object types:
+
+ PersistentList -- This type works just like a list, except that
+ changing it does not require setting _p_changed or explicitly
+ re-assigning the attribute.
+
+ PersistentMapping -- A persistent aware dictionary, much like
+ PersistentList.
+
+ BTree -- A dictionary-like object that can hold large
+ collections of objects in an ordered, fast, efficient way.
+
+ BTrees offer a very powerful facility to the
+ Python programmer:
+
+ o BTrees can hold a large collection of information in an
+ efficient way; more objects than your computer has enough
+ memory to hold at one time.
+
+ o BTrees are integrated into the persistence machinery to work
+ effectively with ZODB's object cache. Recently, or heavily
+ used objects are kept in a memory cache for speed.
+
+ o BTrees can be searched very quickly, because they are stored
+ in an fast, balanced tree data structure.
+
+ BTrees come in three flavors, OOBTrees, IOBTrees, OIBTrees, and
+ IIBTrees. The last three are optimized for integer keys, values,
+ and key-value pairs, respectively. This means that, for example,
+ an IOBTree is meant to map an integer to an object, and is
+ optimized for having integers keys.
+
+ Using BTrees
+
+ Suppose you track the movement of all your employees with
+ heat-seeking cameras hidden in the ceiling tiles. Since your
+ employees tend to frequently congregate against you, all of the
+ tracking information could end up to be a lot of data, possibly
+ thousands of coordinates per day per employee. Further, you want
+ to key the coordinate on the time that it was taken, so that you
+ can only look at where your employees were during certain times::
+
+ from BTrees import IOBTree
+ from time import time
+
+ class Employee(Persistent):
+
+ def __init__(self):
+ self.movements = IOBTree()
+
+ def fix(self, coords):
+ "get a fix on the employee"
+ self.movements[int(time())] = coords
+
+ def trackToday(self):
+ "return all the movements of the
+ employee in the last 24 hours"
+ current_time = int(time())
+ return self.movements.items(current_time - 86400,
+ current_time)
+
+
+ In this example, the 'fix' method is called every time one of your
+ cameras sees that employee. This information is then stored in a
+ BTree, with the current 'time()' as the key and the 'coordinates'
+ as the value.
+
+ Because BTrees store their information is a ordered structure,
+ they can be quickly searched for a range of key values. The
+ 'trackToday' method uses this feature to return a sequence of
+ coordinates from 24 hours hence to the present.
+
+ This example shows how BTrees can be quickly searched for a range
+ of values from a minimum to a maximum, and how you can use this
+ technique to oppress your workforce. BTrees have a very rich API,
+ including doing unions and intersections of result sets.
+
+ Not All Objects are Persistent
+
+ You don't have to make all of your objects persistent.
+ Non-persistent objects are often useful to represent either
+ "canned" behavior (classes that define methods but no state), or
+ objects that are useful only as a "cache" that can be thrown away
+ when your persistent object is deactivated (removed from memory
+ when not used).
+
+ ZODB provides you with the ability to have *volatile* attributes.
+ Volatile attributes are attributes of persistent objects that are
+ never saved in the database, even if they are capable of being
+ persistent. Volatile attributes begin with '_v_' are good for
+ keeping cached information around for optimization. ZODB also
+ provides you with access to special pickling hooks that allow you
+ to set volatile information when an object is activated.
+
+ Imagine you had a class that stored a complex image that you
+ needed to calculate. This calculation is expensive. Instead of
+ calculating the image every time you called a method, it would be
+ better to calculate it *once* and then cache the result in a
+ volatile attribute::
+
+ def image(self):
+ "a large and complex image of the terrain"
+ if hasattr(self, '_v_image'):
+ return self._v_image
+ image=expensive_calculation()
+ self._v_image=image
+ return image
+
+ Here, calling 'image' the first time the object is activated will
+ cause the method to do the expensive calculation. After the first
+ call, the image will be cached in a volatile attribute. If the
+ object is removed from memory, the '_v_image' attribute is not
+ saved, so the cached image is thrown away, only to be recalculated
+ the next time you call 'image'.
+
+ ZODB and Concurrency
+
+ Different, threads, processes, and computers on a network can open
+ connections to a single ZODB object database. Each of these
+ different processes keeps its own copy of the objects that it uses
+ in memory.
+
+ The problem with allowing concurrent access is that conflicts can
+ occur. If different threads try to commit changes to the same
+ objects at the same time, one of the threads will raise a
+ ConflictError. If you want, you can write your application to
+ either resolve or retry conflicts a reasonable number of times.
+
+ Zope will retry a conflicting ZODB operation three times. This is
+ usually pretty reasonable behavior. Because conflicts only happen
+ when two threads write to the same object, retrying a conflict
+ means that one thread will win the conflict and write itself, and
+ the other thread will retry a few seconds later.
+
+ Pluggable Storages
+
+ Different processes and computers can connection to the same
+ database using a special kind of storage called a 'ClientStorage'.
+ A 'ClientStorage' connects to a 'StorageServer' over a network.
+
+ In the very beginning, you created a connection to the database by
+ first creating a storage. This was of the type 'FileStorage'.
+ Zope comes with several different back end storage objects, but
+ one of the most interesting is the 'ClientStorage' from the Zope
+ Enterprise Objects product (ZEO).
+
+ The 'ClientStorage' storage makes a TCP/IP connection to a
+ 'StorageServer' (also provided with ZEO). This allows many
+ different processes on one or machines to work with the same
+ object database and, hence, the same objects. Each process gets a
+ cached "copy" of a particular object for speed. All of the
+ 'ClientStorages' connected to a 'StorageServer' speak a special
+ object transport and cache invalidation protocol to keep all of
+ your computers synchronized.
+
+ Opening a 'ClientStorage' connection is simple. The following
+ code creates a database connection and gets the root object for a
+ 'StorageServer' listening on "localhost:12345"::
+
+ from ZODB import DB
+ from ZEO import ClientStorage
+ storage = ClientStorage.ClientStorage('localhost', 12345)
+ db = DB( storage )
+ connection = db.open()
+ root = connection.root()
+
+ In the rare event that two processes (or threads) modify the same
+ object at the same time, ZODB provides you with the ability to
+ retry or resolve these conflicts yourself.
+
+ Resolving Conflicts
+
+ If a conflict happens, you have two choices. The first choice is
+ that you live with the error and you try again. Statistically,
+ conflicts are going to happen, but only in situations where objects
+ are "hot-spots". Most problems like this can be "designed away";
+ if you can redesign your application so that the changes get
+ spread around to many different objects then you can usually get
+ rid of the hot spot.
+
+ Your second choice is to try and *resolve* the conflict. In many
+ situations, this can be done. For example, consider the following
+ persistent object::
+
+ class Counter(Persistent):
+
+ self.count = 0
+
+ def hit(self):
+ self.count = self.count + 1
+
+ This is a simple counter. If you hit this counter with a lot of
+ requests though, it will cause conflict errors as different threads
+ try to change the count attribute simultaneously.
+
+ But resolving the conflict between conflicting threads in this
+ case is easy. Both threads want to increment the self.count
+ attribute by a value, so the resolution is to increment the
+ attribute by the sum of the two values and make both commits
+ happy.
+
+ To resolve a conflict, a class should define an
+ '_p_resolveConflict' method. This method takes three arguments.
+
+ 'oldState' -- The state of the object that the changes made by
+ the current transaction were based on. The method is permitted
+ to modify this value.
+
+ 'savedState' -- The state of the object that is currently
+ stored in the database. This state was written after 'oldState'
+ and reflects changes made by a transaction that committed
+ before the current transaction. The method is permitted to
+ modify this value.
+
+ 'newState' -- The state after changes made by the current
+ transaction. The method is *not* permitted to modify this
+ value. This method should compute a new state by merging
+ changes reflected in 'savedState' and 'newState', relative to
+ 'oldState'.
+
+ The method should return the state of the object after resolving
+ the differences.
+
+ Here is an example of a '_p_resolveConflict' in the 'Counter'
+ class::
+
+ class Counter(Persistent):
+
+ self.count = 0
+
+ def hit(self):
+ self.count = self.count + 1
+
+ def _p_resolveConflict(self, oldState, savedState, newState):
+
+ # Figure out how each state is different:
+ savedDiff= savedState['count'] - oldState['count']
+ newDiff= newState['count']- oldState['count']
+
+ # Apply both sets of changes to old state:
+ return oldState['count'] + savedDiff + newDiff
+
+ In the above example, '_p_resolveConflict' resolves the difference
+ between the two conflicting transactions.
+
+ Transactions and Subtransactions
+
+ Transactions are a very powerful concept in databases.
+ Transactions let you make many changes to your information as if
+ they were all one big change. Imagine software that did online
+ banking and allowed you to transfer money from one account to
+ another. You would do this by deducting the amount of the
+ transfer from one account, and adding that amount onto the
+ other.
+
+ If an error happened while you were adding the money to the
+ receiving account (say, the bank's computers were unavailable),
+ then you would want to abort the transaction so that the state of
+ the accounts went back to the way they were before you changed
+ anything.
+
+ To abort a transaction, you need to call the 'abort' method of the
+ transactions object::
+
+ get_transaction().abort()
+
+ This will throw away all the currently changed objects and start a
+ new, empty transaction.
+
+ Subtransactions, sometimes called "inner transactions", are
+ transactions that happen inside another transaction.
+ Subtransactions can be commited and aborted like regular "outer"
+ transactions. Subtransactions mostly provide you with an
+ optimization technique.
+
+ Subtransactions can be commited and aborted. Commiting or
+ aborting a subtransaction does not commit or abort its outer
+ transaction, just the subtransaction. This lets you use many,
+ fine-grained transactions within one big transaction.
+
+ Why is this important? Well, in order for a transaction to be
+ "rolled back" the changes in the transaction must be stored in
+ memory until commit time. By commiting a subtransaction, you are
+ telling Zope that "I'm pretty sure what I've done so far is
+ permenant, you can store this subtransaction somewhere other than
+ in memory". For very, very large transactions, this can be a big
+ memory win for you.
+
+ If you abort an outer transaction, then all of its inner
+ subtransactions will also be aborted and not saved. If you abort
+ an inner subtransaction, then only the changes made during that
+ subtransaction are aborted, and the outer transaction is *not*
+ aborted and more changes can be made and commited, including more
+ subtransactions.
+
+ You can commit or abort a subtransaction by calling either
+ commit() or abort() with an argument of 1::
+
+ get_transaction().commit(1) # or
+ get_transaction().abort(1)
+
+ Subtransactions offer you a nice way to "batch" all of your "all
+ or none" actions into smaller "all or none" actions while still
+ keeping the outer level "all or none" transaction intact. As a
+ bonus, they also give you much better memory resource performance.
+
+ Conclusion
+
+ ZODB offers many advanced features to help you develop simple, but
+ powerful python programs. In this article, you used some of the
+ more advanced features of ZODB to handle different application
+ needs, like storing information in large sets, using the database
+ concurrently, and maintaining transactional integrity. For more
+ information on ZODB, join the discussion list at zodb-dev at zope.org
+ where you can find out more about this powerful component of Zope.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
More information about the Checkins
mailing list