[ZODB-Dev] ZODB 3.2.4 ConnectionStateError

Tim Peters tim at zope.com
Wed Nov 3 15:42:32 EST 2004


[Syver Enstad]
> I've been using ZODB 3.2 like this:
>
> connection = db.open(waitflag=False)
> connection.setLocalTransaction()
> connection.sync()
>
> do stuff with connection and sometimes commit the transaction
> connection.close()


> In the case of not commiting the transaction I now get
> ConnectionStateError when I close the connection.

Good -- you're supposed to now.  A transaction in progress must be
explicitly finished now (via commit() or abort() or begin()) before any
connection registered with the transaction will allow itself to be closed.
Else you're leaving the connection in a state where it's impossible to
*guess* what your intent was.

> Am I right in assuming that the connection.sync() call I always do is no
> longer needed in 3.2.4?

Sorry, I can't guess.  Why were you calling it before?  Possibilities
include:

- You're running a ZEO client, not running an asyncore mainloop, and
  needed to sync() manually in order to process invalidation messages
  from the ZEO server.  If so, then you still need to sync() manually.

- You're calling sync() "because it didn't work otherwise"; i.e., you
  don't know why you were calling it, you just know that things worked
  better when you did.

It just so happens that the implementation of sync() first aborts the
current transaction, so in the latter case it's possible things would have
worked just as well had you explicitly aborted the transaction instead of
sync'ing.

Can't guess from here which (if any) applies in your case.  Probably the
latter.

> In my case it would be just as well if connection.close() just called
> self.getTransaction().abort(), but I guess there are cases that others
> use where this is not suitable.

That's right, your intent is ambiguous in this case, and
ConnectionStateError is a major feature to stop you from screwing yourself.
For example, perhaps many storages were involved in the current transaction,
and then implicitly aborting the entire transaction just because someone was
sloppy with objects from a single connection could be a disaster.  If you
don't want to retain the changes you made, abort().  If you want to retain
them, commit().  It's impossible for ZODB to guess the intent; it may also
be impossible for you to guess your intent, but ZODB will no longer spare
you from trying your best to understand what you want <wink>.

> Is it safe to access objects in the connection after one has called
> abort?

You're never *not* "in" a transaction.  The instant abort() returns, a new
transaction has implicitly begun.  So, yes, it's safe to access objects
after aborting, but you're technically in a new transaction then.  If you
modify any of these objects, you'll again need to abort or commit the
transaction before closing the connection.

> If my assumptions are right I guess I have to do my interactions with
> ZODB 3.2.4 like this:
>
> connection = db.open(waitflag=False)
> connection.setLocalTransaction()
>
> do stuff with connection and always either commit or abort the
> transaction
> connection.close()

A transaction that modified any objects must be explicitly completed now
before any connection with a modified object can be closed.  That's true in
ZODB 3.2.4 and in ZODB 3.3, and is true regardless of how the connection was
obtained, and regardless of which transaction manager is used.  So the first
two lines above are really irrelevant to the conclusion (waitflag doesn't
make a difference, and whether or not you use setLocalTransaction() doesn't
make a difference -- if you modify an object, you have to explicitly finish
the transaction, period).



More information about the ZODB-Dev mailing list