Announcement Announcement Module
Collapse
No announcement yet.
Request-level transactions for loading, binding and persisti Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Request-level transactions for loading, binding and persisti

    One of the nice things about Spring's MVC (SimpleFormController) is the ability to bind data directly to a domain (entity) object's bean properties.

    So, going through what happens in handleRequest:
    1) In formBackingobject, let us assume we load the entity from a transactionalized service layer.

    2) The entity's simple properties are bound automatically.

    3) In onBind, we manipulate some of the entity's collections.
    If we don't use OpenSessionInView, we'll get a "[net.sf.hibernate.LazyInitializationException] - Failed to lazily initialize a collection - no session or session was closed."
    So, for now we'll use OpenSessionInView, with singleSession = false.

    4) However, in onSubmit, when we pass this domain object into a transactionalized service-layer "modify" method, we now get an "[net.sf.hibernate.HibernateException] Illegal attempt to associate a collection with two open sessions".

    Now, what we really wanted to do here was to enclose the whole request into a transaction, so that the service-layer loading, Spring binding and service-layer persistence all use the same session within the same transaction.

    So, my solution is to transactionalize the FormController itself, and specifically it's handleRequest method.
    This does away with the need for OpenSessionInView (we can still use it as it was meant of course, for lazy collection access in the View).
    It seems to work perfectly well as far as Hibernate is concerned, but is it kosher?

    Best regards,
    Assaf

  • #2
    Sure, it will work, and it's a nice consequence of IoC management of web tier objects that it's possible, but I stil find it a bit questionable. I just don't like the idea of transactions--which are a business layer issue--being managed from UI code. However, there may not be so many strong arguments against what you're doing, and if it's working for you, it's defensible :-) It could limit reuse of your business objects, as they won't work properly without the UI tier driving transactions.

    Comment


    • #3
      If this approach is "questionable", my other option seems to be to create a UI object graph with near-identical properties to the domain objects, allow Spring to bind to the UI objects instead of domain objects, and then pass these UI objects into the service layer to be "cloned" onto the persistent domain objects.

      This would effectively keep transactions at the service layer, where they belong, but it would seem a shame to create this parallel object graph and especially to write all of the cloning code when my gut feeling is that domain objects, representing the primary business entities of the problem domain, should be available to all layers: DAO, service and UI.

      Is this the approach most people are taking? Or am I missing something here?

      Best regards,
      Assaf

      Comment


      • #4
        Just a note to explain what I settled on:
        Basically, I wanted to maintain two architectural principles, if at all possible:
        1) lazy-load the collections
        2) manipulate domain objects on all levels: DAO, Service, UI

        On the other hand, it does seem a shame to transactionalize the handleRequest call in the UI layer, since it breaks the layering abstraction.

        To do away with UI-layer transactions, two things had to be done:
        a) get rid of OpenSessionInView completely, to avoid "Illegal attempt to associate a collection with two open sessions" when sending an existing domain object back into a service-level call (e.g. after binding by Spring).
        b) provide methods to touch any required collections in the Service layer - I settled on two methods for doing this - one which touches all of an object's collections when first loading it (but not its children's collections), and another to be used for an already-loaded object (e.g. initially loaded as a child in a collection).
        The latter method first reconnects the object:
        Code:
        this.getHibernateTemplate().lock(entity, LockMode.NONE);
        and then touches its collections.

        So, now I can keep transactions on the service layer without incurring either the "two open sessions" error, or (if I'm careful) the "Failed to lazily initialize a collection".

        However, the latter error can still occur at runtime anytime an entity's collections haven't been "touched" ahead of time. This still seems better than doing away with lazy-loading completely and constructing a whole object graph at every database load.

        I'd be interested to know how others have dealt with this.
        Best regards,
        Assaf

        Comment


        • #5
          you got it. That is exactly how I do it in my apps.

          There are alternatives to it though. I have been playing around with AspectJ to enable transparent collection touching and current version verification, but have not had much time to finish anything.

          People are also talking about spring managed hibernate created objects, that you might want to take a look at, here:

          http://forum.springframework.org/showthread.php?t=9846
          Last edited by robyn; May 14th, 2006, 11:49 AM.

          Comment


          • #6
            The DependencyInjectionInterceptorFactoryBean is very useful, especially for things like wiring an application context-managed Validator into each domain object instance, allowing it to self-manage its own validation.

            Comment


            • #7
              Originally posted by bpolka
              There are alternatives to it though. I have been playing around with AspectJ to enable transparent collection touching and current version verification, but have not had much time to finish anything.
              Interesting idea... Just read through a bit of AspectJ documentation to see how it might work. All I was able to imagine so far was an aspect for reconnecting an entity whenever lazy instantiation was required. Since I can't even claim to be an AspectJ newbie, that might be very naive on my behalf.... Something like:
              Code:
              aspect ReconnectWhenNeeded {
                  pointcut getCollection(Entity entity):
                      (target(entity) &&
                      (call(List com.blah.domain.*.get*()) || 
                      call(Set com.blah.domain.*.get*()) ||
                      call(Map com.blah.domain.*.get*())));
              
                  before(Entity entity): getCollection(entity){
                      // somehow transactionalize this call and associate entity with current session
                      // equivalent of this.getHibernateTemplate().lock(entity, LockMode.NONE) in a DAO
                  }
              }
              Is this anything close to what you had in mind?
              Can AspectJ aspects be wired with Spring?

              I'm not sure how you'd use spring-managed hibernate entities (i.e. DependencyInjectionInterceptorFactoryBean) to enable on-demand collection touching... short of giving the entity a reference to a service object, and then starting every public getPersistentCollection method with a call to the service.reconnect(entity), which gets the DAO to reconnect the entity. Sound a bit convoluted! But if anybody has a suggestion here, I'd be interested in exploring it.

              Best regards,
              Assaf

              Comment


              • #8
                Originally posted by Ben Alex
                The DependencyInjectionInterceptorFactoryBean is very useful, especially for things like wiring an application context-managed Validator into each domain object instance, allowing it to self-manage its own validation.
                I've read the post and example for use of the DependencyInjectionInterceptorFactoryBean (http://forum.springframework.org/showthread.php?t=9846) and am interested in using it to wire dao's to some of my persistent Hibernate objects. However, Spring version 1.2.3 does not seem to include this class (?).

                I discovered that the port of this class to support Hibernate 3 is yet to be released (http://opensource.atlassian.com/proj...rowse/SPR-1163), but it seems like from reading the forum, the class for Hibernate 2.x was in a previous Spring release (?). However, I don't see the class in the ...orm/hibernate/support package.

                If anyone can tell a nubie what I'm missing, I would greatly appreciate it.
                Last edited by robyn; May 15th, 2006, 05:46 PM.

                Comment


                • #9
                  Originally posted by specise
                  However, Spring version 1.2.3 does not seem to include this class (?).
                  You will need to check out the source from CVS. The class is located in the sandbox, but it is not packaged in binary form as part of the Spring release.

                  Comment


                  • #10
                    Originally posted by cepage
                    You will need to check out the source from CVS. The class is located in the sandbox, but it is not packaged in binary form as part of the Spring release.
                    There is a reference to this class in chapter 1 of "Professional Java Development with the Spring Framework" (which is where I first found out about it), so I assumed the class was already in a production release.

                    Thanks! I'll grab it from CVS and give it a whirl.

                    Comment

                    Working...
                    X