http://dev.clojure.org/jira/browse/JDBC-11
The current code is shown below but the crux of the issue is that if
an Error occurs during processing of the SQL operation (or
user-supplied expression executed in that context), the library code
still attempts to commit the transaction. That's intuitively wrong but
there is some argument that "all bets are off" in the event of an
Error rather than an Exception. My initial reaction would be to catch
Throwable, set rollback true, and rethrow but looking at the current
handling of Exception, I noticed it wraps the original exception and
throws that... which also feels a bit wrong to me: shouldn't the
original exception be thrown without arbitrary wrapping?
So, two questions to the group:
1) is it reasonable to catch Throwable at all?
2) is it reasonable to wrap Exceptions like that?
I think I'm leaning toward removing the finally (pushing that code
into a function called in both the try body and a catch on Exception),
and letting Throwable escape without attempting to clean up at all.
I'm also leaning toward not wrapping the Exception on transaction
rollback - I don't see any concrete benefit to that (perhaps Stephen
can shed some insight there since he wrote the original code?).
Thanx for any input on this.
Sean
(defn throw-rollback
"Sets rollback and throws a wrapped exception"
[e]
(rollback true)
(throw (Exception. (format "transaction rolled back: %s" (.getMessage e)) e)))
(defn transaction*
"Evaluates func as a transaction on the open database connection. Any
nested transactions are absorbed into the outermost transaction. By
default, all database updates are committed together as a group after
evaluating the outermost body, or rolled back on any uncaught
exception. If rollback is set within scope of the outermost transaction,
the entire transaction will be rolled back rather than committed when
complete."
[func]
(binding [*db* (update-in *db* [:level] inc)]
(if (= (:level *db*) 1)
(let [con (connection*)
auto-commit (.getAutoCommit con)]
(io!
(.setAutoCommit con false)
(try
(func)
(catch Exception e
(throw-rollback e))
(finally
(if (rollback)
(.rollback con)
(.commit con))
(rollback false)
(.setAutoCommit con auto-commit)))))
(func))))
1) is it reasonable to catch Throwable at all?
2) is it reasonable to wrap Exceptions like that?
2) is it reasonable to wrap Exceptions like that?
Yes. Java libraries do it all over the place. As long as you don't "swallow" the original exception, you can wrap it in another exception.
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it.
--
You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
To post to this group, send email to cloju...@googlegroups.com.
To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.