Fixes #34 by adding save point tests
And updating the Transactions documentation to show save point examples.
This commit is contained in:
parent
1cec0a2643
commit
1fe7e92df2
3 changed files with 50 additions and 0 deletions
|
|
@ -9,6 +9,7 @@ The following changes have been committed to the **master** branch since the 1.0
|
|||
* Fix #37 by adjusting the spec for `with-transaction` to "require less" of the `:binding` vector.
|
||||
* Fix #36 by adding type hint in `with-transaction` macro.
|
||||
* Fix #35 by explaining the database-specific options needed to ensure `insert-multi!` performs a single, batched operation.
|
||||
* Fix #34 by explaining save points (in the Transactions documentation).
|
||||
|
||||
## Stable Builds
|
||||
|
||||
|
|
|
|||
|
|
@ -47,4 +47,31 @@ Instead of throwing an exception (which will propagate through `with-transaction
|
|||
(jdbc/execute! tx ...))))
|
||||
```
|
||||
|
||||
## Save Points Inside a Transaction
|
||||
|
||||
In general, transactions are per-connection and do not nest in JDBC. If you nest calls to `with-transaction` using a `DataSource` argument (or a db-spec) then you will get separate connections inside each invocation and the transactions will be independent, as permitted by the isolation level.
|
||||
|
||||
If you nest such calls passing a `Connection` instead, the inner call will commit (or rollback) all operations on that connection up to that point -- including any performed in the outer call, prior to entering the inner call. The outer call will then commit (or rollback) any additional operations within its scope. This will be confusing at best and most likely buggy behavior!
|
||||
|
||||
If you want the ability to selectively roll back certain groups of operations inside a transaction, you can use named or unnamed save points:
|
||||
|
||||
```clojure
|
||||
(jdbc/with-transaction [tx my-datasource]
|
||||
(let [result (jdbc/execute! tx ...) ; op A
|
||||
sp1 (.setSavepoint)] ; unnamed save point
|
||||
|
||||
(jdbc/execute! tx ...) ; op B
|
||||
|
||||
(when ... (.rollback tx sp1)) ; just rolls back op B
|
||||
|
||||
(let [sp2 (.setSavepoint "two")] ; named save point
|
||||
|
||||
(jdbc/execute! tx ...) ; op C
|
||||
|
||||
(when ... (.rollback tx sp2))) ; just rolls back op C
|
||||
|
||||
result)) ; returns this and will commit op A
|
||||
;; (and ops B & C if they weren't rolled back above)
|
||||
```
|
||||
|
||||
[<: Prepared Statements](/doc/prepared-statements.md) | [All The Options :>](/doc/all-the-options.md)
|
||||
|
|
|
|||
|
|
@ -136,6 +136,28 @@ VALUES ('Pear', 'green', 49, 47)
|
|||
"])]
|
||||
(.rollback t)
|
||||
result))))
|
||||
(is (= 4 (count (jdbc/execute! (ds) ["select * from fruit"])))))
|
||||
(testing "with-transaction with unnamed save point"
|
||||
(is (= [{:next.jdbc/update-count 1}]
|
||||
(jdbc/with-transaction [t (ds)]
|
||||
(let [save-point (.setSavepoint t)
|
||||
result (jdbc/execute! t ["
|
||||
INSERT INTO fruit (name, appearance, cost, grade)
|
||||
VALUES ('Pear', 'green', 49, 47)
|
||||
"])]
|
||||
(.rollback t save-point)
|
||||
result))))
|
||||
(is (= 4 (count (jdbc/execute! (ds) ["select * from fruit"])))))
|
||||
(testing "with-transaction with named save point"
|
||||
(is (= [{:next.jdbc/update-count 1}]
|
||||
(jdbc/with-transaction [t (ds)]
|
||||
(let [save-point (.setSavepoint t (name (gensym)))
|
||||
result (jdbc/execute! t ["
|
||||
INSERT INTO fruit (name, appearance, cost, grade)
|
||||
VALUES ('Pear', 'green', 49, 47)
|
||||
"])]
|
||||
(.rollback t save-point)
|
||||
result))))
|
||||
(is (= 4 (count (jdbc/execute! (ds) ["select * from fruit"]))))))
|
||||
|
||||
(deftest plan-misuse
|
||||
|
|
|
|||
Loading…
Reference in a new issue