[Checkins] SVN: zope2docs/trunk/ moved

Andreas Jung andreas at andreas-jung.com
Sat Feb 21 03:42:50 EST 2009


Log message for revision 96870:
  moved
  

Changed:
  D   zope2docs/trunk/ZODB1.rst
  D   zope2docs/trunk/ZODB2.rst
  A   zope2docs/trunk/articles/
  A   zope2docs/trunk/articles/ZODB1.rst
  A   zope2docs/trunk/articles/ZODB2.rst

-=-
Deleted: zope2docs/trunk/ZODB1.rst
===================================================================
--- zope2docs/trunk/ZODB1.rst	2009-02-21 08:32:31 UTC (rev 96869)
+++ zope2docs/trunk/ZODB1.rst	2009-02-21 08:42:50 UTC (rev 96870)
@@ -1,400 +0,0 @@
-Introduction to the ZODB (by Michel Pelletier)
-==============================================
-
-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
-
-
-
-
-
-
-
-

Deleted: zope2docs/trunk/ZODB2.rst
===================================================================
--- zope2docs/trunk/ZODB2.rst	2009-02-21 08:32:31 UTC (rev 96869)
+++ zope2docs/trunk/ZODB2.rst	2009-02-21 08:42:50 UTC (rev 96870)
@@ -1,364 +0,0 @@
-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:
-
--   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.  
-
--   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.
-
--   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.
-
-
-

Copied: zope2docs/trunk/articles/ZODB1.rst (from rev 96868, zope2docs/trunk/ZODB1.rst)
===================================================================
--- zope2docs/trunk/articles/ZODB1.rst	                        (rev 0)
+++ zope2docs/trunk/articles/ZODB1.rst	2009-02-21 08:42:50 UTC (rev 96870)
@@ -0,0 +1,400 @@
+Introduction to the ZODB (by Michel Pelletier)
+==============================================
+
+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
+
+
+
+
+
+
+
+

Copied: zope2docs/trunk/articles/ZODB2.rst (from rev 96868, zope2docs/trunk/ZODB2.rst)
===================================================================
--- zope2docs/trunk/articles/ZODB2.rst	                        (rev 0)
+++ zope2docs/trunk/articles/ZODB2.rst	2009-02-21 08:42:50 UTC (rev 96870)
@@ -0,0 +1,364 @@
+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:
+
+-   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.  
+
+-   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.
+
+-   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