Yeah, that is the conclusion I came to, dynamic binding for the win, I think :). On 4 Mar 2015 18:47, <[email protected]> wrote:
> (if it's just a regular ThreadLocal, you should be able to get its value > through (.get tx)) > > To elucidate briefly, I mean something like this: > > (def ^:dynamic *tx*) > > ;; elsewhere > (binding [*tx* (.get tx)] > ...do stuff > ...cleanup) > > a with-tx macro would make this pattern reusable throughout your code. > > On Wednesday, March 4, 2015 at 1:43:36 PM UTC-5, [email protected] > wrote: >> >> Ah I think I understand now! Is it possible to dereference the connection >> and "hold on" to the thread local state? If so, then dynamically binding >> the transactional connection and doing all of your work within that context >> might be a good solution. You can also write a macro to do this, >> closing/doing cleanup of the connection before exiting the dynamic scope of >> your transaction. >> >> On Wednesday, March 4, 2015 at 1:15:02 PM UTC-5, Colin Yates 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, <[email protected]> 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 [email protected] >>> > Note that posts from new members are moderated - please be patient >>> with your >>> > first post. >>> > To unsubscribe from this group, send email to >>> > [email protected] >>> > 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 [email protected]. >>> > 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 [email protected] > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > [email protected] > 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 [email protected]. > 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 [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] 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 [email protected]. For more options, visit https://groups.google.com/d/optout.
