I'm calling the clojure.lang.Ref and LockingTransaction classes
directly from Java (as suggested by Rich above).
Yes, as Daniel says you to need to segregate side effects from the
code that runs in a transaction. I'm using some lightweight wrappers
around Ref and LockingTransaction to store a queue of side effects,
all of which get run on commit of the outer-most transaction (similar
to the use of agents, which aren't exposed in the Java classes IIRC).
The approach works well in practice, minor pain points so far have
been Java's handling of checked exceptions (which doesn't fit well
with functional programming), and selecting the right library of
immutable data structures to work with from Java. Google collections
have a fantastic API and support generics (but aren't persistent so
you have to do copy on write); Clojure's data structures are
wonderful, but don't use generics. pcollections[1] appears to fill the
gap, but not sure what state that project is in.
[1]
http://code.google.com/p/pcollections/