diff --git a/src/main/clojure/clojure/java/jdbc/internal.clj b/src/main/clojure/clojure/java/jdbc/internal.clj
index 4d79cb5..ee96e3b 100644
--- a/src/main/clojure/clojure/java/jdbc/internal.clj
+++ b/src/main/clojure/clojure/java/jdbc/internal.clj
@@ -158,7 +158,7 @@
   "Sets rollback and throws a wrapped exception"
   [e]
   (rollback true)
-  (throw (Exception. (format "transaction rolled back: %s" (.getMessage e)) e)))
+  (throw e))
 
 (defn transaction*
   "Evaluates func as a transaction on the open database connection. Any
@@ -177,7 +177,7 @@
           (.setAutoCommit con false)
           (try
             (func)
-            (catch Exception e
+            (catch Throwable e
               (throw-rollback e))
             (finally
               (if (rollback)
diff --git a/src/test/clojure/clojure/java/test_jdbc.clj b/src/test/clojure/clojure/java/test_jdbc.clj
index 3b73a7b..cdfcf43 100644
--- a/src/test/clojure/clojure/java/test_jdbc.clj
+++ b/src/test/clojure/clojure/java/test_jdbc.clj
@@ -85,6 +85,74 @@
       (is (re-find (pattern "Message: Test Message.*Message: Base Message") except-str))
       (is (re-find (pattern "SQLState: Test State.*SQLState: Base State") except-str)))))
 
+(defn register-call
+  "Registers a call in the call map. Create a new call map calling (call-map)"
+  [call-map mock method args]
+  (swap! call-map update-in [mock method] conj args))
+
+(defmacro defmock
+  "Defines a function fun-name which reifies the interface ifx.
+  methods have the same form as in a reify call. call-map-sym will
+  be binded to the call-map for its use in method bodies.
+  All methods calls will be registered in call-map-sym, which should be created
+  with (call-map)."
+  [fun-name ifx call-map-sym & methods]
+  (let [def-method (fn [[meth-name args & body]]
+                     `(~meth-name ~args
+                         (register-call ~call-map-sym
+                                        ~(keyword fun-name)
+                                        ~(keyword meth-name)
+                                        ~(vec (rest args)))
+                         ~@body))
+        methods (map def-method methods)]
+  `(defn ~fun-name [~call-map-sym]
+     (reify ~ifx ~@methods))))
+
+(defmock mock-statement java.sql.PreparedStatement call-map
+  (close [this])
+  (setObject [this idx x])
+  (addBatch [this])
+  (addBatch [this sql])
+  (executeBatch [this]))
+
+(defmock mock-connection java.sql.Connection call-map
+  (close [this])
+  (getAutoCommit [this] false)
+  (setAutoCommit [this auto])
+  (commit [this])
+  (prepareStatement [this sql] (mock-statement call-map))
+  (rollback [this]))
+
+(defn mock-factory
+  "Create a fake connection factory, it will return a mock-connection"
+  [call-map]
+  (fn [spec]
+    (register-call call-map :mock-factory "()" [spec])
+    (mock-connection call-map)))
+
+(defn calls-to
+  "Given a call map returns a list of calls to method in mock object."
+  [call-map mock method]
+  (-> @call-map mock method))
+
+(defn call-map
+  "Create a new call map"
+  [] (atom {}))
+
+(deftest test-rollback-on-error
+  (let [calls (call-map)
+        thr (Throwable.)]
+    (try
+      (sql/with-connection {:factory (mock-factory calls)}
+        (sql/transaction
+          (throw thr)))
+      (catch Throwable t
+        (is (identical? thr t) "The same exception is thrown")))
+    (is (= 1 (count (calls-to calls :mock-connection :rollback)))
+        "rollback is called once")
+    (is (= 0 (count (calls-to calls :mock-connection :commit)))
+        "commit is not called")))
+
 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; old example code below here - will eventually be removed once proper tests are written!
 
