In my previous project we were using high order functions to wrap
everything in a transaction.

So we would have stuff like this:

(require [clojure.java.jdbc :as db])

(defn create-foo-entity [entity]
  [(fn [conn] (db/insert! ...))])

(defn create-bar-entity [entity]
  [(fn [conn] (db/insert! ...)) (fn [conn] (db/update! ...))])

(defn execute-sql [sql-fns]
  (db/with-db-transaction ... (dorun (map #(statement conn) sql-fns))))

(execute-sql (concat (create-foo-entity entity1) (create-bar-entity entity2))

​




*--*
*Eduardo Aquiles Radanovitsck*
ThoughtWorks Brasil

On Wed, Mar 4, 2015 at 3:14 PM, Colin Yates <colin.ya...@gmail.com> wrote:

> Hi Adrian, and thanks for replying.
>
> I understand your point, but the subtlety is that a transactional
> connection is per function invocation where as the database component
> is per Component lifecycle - passing the db around isn't sufficient
> here.
>
> Spring plumbing binds a transactional connection to a thread local and
> then passes a connection proxy around - accessing that proxy magically
> (through the use of the lovely AOP) resolves to the current
> thread-local transactional connection.
>
> I don't see any option other than to re-implement that in Clojure or
> pass an explicit 'unit-of-work' around but it all feels wrong in
> Clojure.
>
> The problem at the moment is that the implementation of each protocol
> will execute in separate transactions.
>
>
>
>
> On 4 March 2015 at 18:06,  <adrian.med...@mail.yu.edu> wrote:
> > Having never used Spring (or anything else resembling the style of code
> you
> > presented) I don't really know if I'm understanding what you're asking.
> >
> > However, it might be useful to wrap your database in a component. I do
> this
> > for Datomic all of the time, and the boilerplate looks something like
> this:
> > https://gist.github.com/aamedina/a1ca5e97c1a5d73fe141. I'm not sure
> exactly
> > how this would fit into JDBC, but I'm sure you can figure it out if you
> > think it would be worthwhile.
> >
> > I then pass the database component to any other component in my system
> that
> > I know will make use of it. If used in a middleware-like scenario (where
> an
> > arbitrary function is passed to the component, possibly composed with
> other
> > functions, and invoked elsewhere), I usually have a convention where I
> pass
> > a map of options as an argument to the handler, and make the database a
> > value in that map.
> >
> >
> > On Wednesday, March 4, 2015 at 12:58:58 PM UTC-5, Colin Yates wrote:
> >>
> >> Hi,
> >>
> >> I am looking for the Clojure equivalent of:
> >>
> >> class Whatever {
> >>     @Transactional
> >>     void doSomething(IDoSomething one, IDoSomethingElse two) {
> >>       one.doSomething()
> >>       two.doSomething()
> >>     }
> >> }
> >>
> >> where both one and two are dependency injected with a proxy which
> resolves
> >> to a thread local database connection. In addition, one might itself
> have a
> >> collaborator which itself has a collaborator which needs a datasource.
> >>
> >> So far I have two protocols:
> >>
> >> (defprotocol IDoSomething
> >>  (do-something [this ...])
> >>
> >> (defprotocol IDoSomethingElse
> >>  (do-something [this ...])
> >>
> >> Each protocol may have a number of implementations, one of which is a
> JDBC
> >> implementation:
> >>
> >> (defrecord JdbcIDoSomething [db]
> >>   (do-something [this ...] ...))
> >>
> >> The problem is that the calling code only gets provided an IDoSomething
> >> and an IDoSomethingElse and it wants to do something like:
> >>
> >> (let [one (->JdbcDoSomething db) two (->JdbcDoSomethingElse db)]
> >>   (with-transaction [tx db]
> >>     (do-something one)
> >>     (do-something-else two)))
> >>
> >> The problem here is that the implementations of do-something and
> >> do-something-else won't have access to the local bound 'tx', they will
> have
> >> their own 'db'.
> >>
> >> I realise the general argument is to be explicit and pass a db as the
> >> first argument to the protocol but this isn't appropriate in this case
> as
> >> there are validly multiple implementations. I could abstract a
> >> 'unit-of-work' and pass that as the first argument to the protocols but
> that
> >> seems a bit painful.
> >>
> >> Also, these protocols may be used quite far away from where the database
> >> code lives and passing a parameter all the way through the call stack is
> >> painful.
> >>
> >> I am using Stuart Sierra's components if that makes any difference.
> >>
> >> I can't be the first person to run into this but google is surprisingly
> >> unhelpful which makes me think I have missed something fundamental, and
> that
> >> I have something upside down.
> >>
> >> What do you all do?
> >>
> >>
> > --
> > You received this message because you are subscribed to the Google
> > Groups "Clojure" group.
> > To post to this group, send email to clojure@googlegroups.com
> > Note that posts from new members are moderated - please be patient with
> your
> > first post.
> > To unsubscribe from this group, send email to
> > clojure+unsubscr...@googlegroups.com
> > For more options, visit this group at
> > http://groups.google.com/group/clojure?hl=en
> > ---
> > You received this message because you are subscribed to the Google Groups
> > "Clojure" group.
> > To unsubscribe from this group and stop receiving emails from it, send an
> > email to clojure+unsubscr...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to