Deprecation problem and ConnectionStateError, was: Re: [ZODB-Dev] Span transaction over several threads

Tim Peters tim at zope.com
Thu Sep 9 19:26:39 EDT 2004


[Diez Roggisch]
>>> Another side-effect of setLocalTransaction() is that when I try to open
>>> a not-yet existing DB,  I get
>>>
>>> ConnectionStateError: Cannot close a connection joined to a transaction

[Tim Peters]
>> Sorry, I don't know what this means.  Post code if you care!
>> Here's my [... example doing that and not seeing a problem  ...]

[Diez]
> I don't want to stress your PSI-capabilities too much  - I guess you'll
> need them for the upcoming lottery night. So I attached some example
> code, that illustrates my problem.

Bingo.  You would get exactly the same exception if you tried this in ZODB
3.2.4c1 (released on Monday).  You cannot close a Connection while
modifications are pending (you were never "supposed to", but ZODB 3.1 and
3.2 didn't enforce that before 3.2.4c1; ZODB 3.3 has always tried to enforce
it).

Anyway, here's the problem:

...
conn = db.open()
conn.setLocalTransaction()

... make a modification ...

get_transaction().commit()
conn.close()

After you do setLocalTransaction(), get_transaction() no longer has anything
to do with the transaction you told the Connection to use.  So your commit()
was essentially a nop (it grabbed the current *thread's* transaction, in
which nothing had been done).  So your changes are still pending, and the
Connection refuses to let you close it.

See the earlier email with my example for a correct way to retrieve the
transaction created by setLocalTransaction().

I sympathize, but not more than that <wink>.  You're *always* "in a
transaction", and the boundaries are often unclear because so much is
implicit.  When you did get_transaction(), that asked the current *thread*
transaction manager for its current transaction.  It looked, saw that it
didn't have one, and created one for you.  Unfortunately, it had nothing to
do with the transaction in progress.

get_transaction() should be deprecated too, BTW.  It's much harder to get
yourself confused if you explicitly name the transaction manager you
*intend* to use, but that wasn't possible before 3.3.  So let's do it the
BraveNewWay:

...
import transaction
tm = transaction.TransactionManager()
conn = db.open(txn_mgr=tm)

... make a modification ...

tm.get().commit()
conn.close()

No problem anymore.  You control the transaction manager explicitly this
way, and you can explicitly ask it for the transaction it's currently
managing.



More information about the ZODB-Dev mailing list