Well, just as a data point, in Zope (where you always get a
transaction whether you like it or not, and aren't given any
control over how it works) this has kicked me in the ass before.
It's also usually nice. But the ass-kicking really sucks. One of
Zope's features is that if you get a conflict error, it'll re-run
the request for you, essentially creating a situation where when
contention gets high you don't require the user to hit submit over
and over, you hit submit over and over *for* the user. Lovely.
In my experience, Zope is a valuable data point for how *not* to do
things. Like you, my ass still has bruises from Zope 2. I hope this
doesn't negate my initial argument :)
That said, there certainly is a genuine appeal to putting
everything in transactions.
Agreed, and it appears that Kevin agrees.
The only other alternative that I can think of, is to
automatically realize when you need to run inside a transaction
by having SQLObject start one automatically when a create,
update, or delete occurs and then have TurboGears commit or
rollback any open transactions at the conclusion of a request
depending on whether or not an "exceptional" Exception occurred.
SQLObject can't current do this, but I don't think this would be
too difficult. Basically you'd create another Transaction
subclass, and it would watch for updating methods, and would only
start using its own transactional connection once one had gone by.
I think this could reduce the likelihood of contention quite a bit,
so long as you aren't too concerned about absolutely isolated
transactions. I.e., your first select may not be consistent with
your second select, but if you run that in a transaction (with the
right isolation) it would be.
Given that this is also possible, it seems like there are several
different ways to do this off the top of my head:
1. WSGI middleware (I think)
2. CherryPy filters
3. SQLObject modifications
4. Decorators
5. Some mixture of the above
What is the best way? I have no idea, but I am intrigued by option
#3, because I thought it might be hard, and it would take into
account the actual use of the model objects automatically... of
course it doesn't take into account anything that happens directly
against the DB not through SQLObject...
That being said, I really don't know what the best option is. Kevin,
have you decided on a direction to take here? How can I help?
There are some open caching issues with transactions as well, that
require some thinking about what has to be expired when. And,
really, transactions could probably make more use of caching than
they currently do.
I am very interested in the direction that you are planning on
taking, and how I can help.
-- Jonathan