practicalli / practicalli/clojure-web-services

database connections no longer use with-connection

Open
#3 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Markdown
Stars
16
Forks
14
PR merge metrics
No merged PRs in 30d

Description

Update: is this still relevant to next.jdbc

https://stackoverflow.com/questions/22586804/with-connection-what-happened

from [org.clojure/java.jdbc "0.3.3"] onwards

with-connection was not only considered harmful for reasons leonardoborges mentioned, it also makes working with connection pools harder. Decoupling function database access from specific connections makes for a much easier model. Forcing queries to use the same connection should be the exception, not the rule. So clojure.core/java.jdbc 0.3.0 was designed specifically to deprecate with-connection. To accomodate that, the whole API needed to be changed.

Each database access function now takes the db spec as a parameter. If the db-spec is a connection pool the function will be executed on one of it's connections, otherwise an implicit new connection is made from the db-spec. So all database access functions result in a connection each when connectionpools are not used.

This also means resultsets can no longer be returned lazily. Formerly, processing lazy sequences could be postponed while still inside the with-connection block. Now they need to be realized during function execution, or its connection could be closed or a new connection could be returned from the pool for the next access function.

So processing can now be done within the scope of the functions themselves, through two new named parameters: :row-fn and :result-set-fn. The first transforms each row, the second the collection of rows. If the :result-set-fn returns a lazy sequence, you will get a connection or resultset closed exception when using it later. The default :result-set-fn is doall. When using your own, make sure it is realized.

So much for the general case, where access and connections are decoupled. Now for the exception: Needing functions to use the same connection.

The most common of these is transaction use, which uses scope to indicate the beginning and the end of the transaction. The old transaction only provided this scope. The new with-db-transaction function takes a binding of a new var and the dp-spec.

This var will be bound to one specific connection from a pool, or when no connection pools are used, a newly created connection. All db access functions used inside the block should use the var instead of the db-spec parameter.

(def db {..})

(with-db-transaction
[c db]
(let [from 1111
to 2222
sum 10
saldo-from (query c ["select saldo from account where id=?" from]
:row-fn :saldo
:result-set-fn first)
saldo-to (query c ["select saldo from account where id=?" to]
:row-fn :saldo
:result-set-fn first)]
(update! c :account {:saldo (- saldo-from sum)} ["id=?" from])
(update! c :account {:saldo (+ saldo-to sum)} ["id=?" to])))
A begin transaction command will be issued at the beginning. All access will use the same connection that's now specifically passed to the functions instead of through dynamic scoping magic. When no exceptions are generated, a commit will be given at the end of the scope.

When one specific connection, but no transaction mechanic is needed, there's the with-db-connection function which has the same semantics. So if you want to execute a command to set a session setting, and do some queries on that connection, you can do the following:

(def db {..})

(with-db-connection [c db]
(execute! c ["alter session set NLS_SORT='ITALIAN'"])
(query c ["select * from person where name=?" "Mario"]
:row-fn (comp concat (juxt :name :surname))))
Connection pools usually have specific on-open and on-close commands that are part of their specs. Using those all connections from that pool will have the same session settings set, and with-db-connection is not even needed at all.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No file, test, or entry point is named. First verify whether this historical discussion still applies to next.jdbc and identify the documentation or examples that need updating; done means the relevant guidance reflects the current connection and transaction APIs.

Written by the indexing model from the issue text.

Assessment

Domain
databases, documentation
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.