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.