Results 1 to 6 of 6

Thread: Issues with methods calling methods with @Transactional

  1. #1
    Join Date
    Jul 2007
    Posts
    101

    Default Issues with methods calling methods with @Transactional

    I am having issues when a method calls a method with the @Transactional. When I do, it appears to be ignored.

    The scenario I have is that I have a base repository class that provides a bunch of convenience methods and they have the @Transactional. If the caller doesn't have @Transactional, it is ignored.

    Example:
    Code:
    @Repository
    public abstract class AbstractRepository {
        @Transactional
        public Object doSomethingCommon(Long pk) throws DataAccessException {
            ...some hibernate code
        }
    }
    
    public FooBarRepository extends AbstractRepository {
    
        public Object doSomethingCommonOnFooBar() {
            doSomethingCommon(foobarId);        
        }
    }
    We use the <tx:annotation-driven/> configuration and inject the FooBarRepository. This will generate the folowing exception:
    Code:
    org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
            at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
            at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:544)
    ....
    Should this work? If I also add the @Transactional to doSomethingOnFooBar(), it works. I would really like to get this to cascade so business logic can call into code without having to always know that somewhere in the code stack there is an @Transactional.

    So, is there a way to get the <tx:annotation-driven/> to proxy more then the top level methods? If so, how do we do it? Is this a bug?

    Hope this is clear.

  2. #2
    Join Date
    Aug 2004
    Posts
    1,905

    Default

    Quick answer, you are using a proxy based approach, you need to use load time weaving (http://static.springframework.org/sp...tml#aop-aj-ltw)

    Long answer:
    The way that Spring "applies" Transactional code (or any AOP advice) is traditionally with proxies, a dynamic decorator if you will. When you ask Spring for your Repository, it will actually give you a newly created class (proxy) which looks like you Repository, so no-body knows it isn't actually your Repository, i.e. it implements all the interfaces.

    When people call a method on the Repository, they are actually calling a method on the Spring created class (a JDK proxy). This method will apply the advice (i.e. start the transaction) and then delegate the call to your actual Repository.

    Clever isn't it The problem is that if you call a method on yourself (as you are doing), it completely bypasses the proxy. This is a restriction with any decorator/proxy based frameworks (EJB, Spring etc.)

    "Weaving" doesn't use proxies, it uses byte code manipulation to apply the advice right into your code. There are two ways of doing this, compile time (you use a special compiler) or load-time. The most convenient is load-time.

    HTH.
    Colin Yates
    SpringSource - http://www.springsource.com - Spring Training, Consulting, and Support - "From the Source"
    Please read http://www.springframework.org/documentation
    Co-Author of Expert Spring MVC + Web Flow.

  3. #3
    Join Date
    Jul 2007
    Posts
    101

    Default

    This helps tremendously and was what I thought was the issue. Your explanation is quite good. I am not sure if the documentation clearly brings this requirement to the surface. Thanks.

  4. #4
    Join Date
    Aug 2006
    Location
    Now Germany, previously Ukraine
    Posts
    1,546

    Default

    Quote Originally Posted by ccanning View Post
    This helps tremendously and was what I thought was the issue. Your explanation is quite good. I am not sure if the documentation clearly brings this requirement to the surface. Thanks.
    Noop, it is documented quite clearly in the part 6.6.1 of spring 2.5.1 Reference, see below.

    This means that method calls on that object reference will be calls on the proxy, and as such the
    proxy will be able to delegate to all of the interceptors (advice) that are relevant to that particular method call.
    However, once the call has finally reached the target object, the SimplePojo reference in this case, any method
    calls that it may make on itself, such as this.bar() or this.foo(), are going to be invoked against the this
    reference, and not the proxy. This has important implications. It means that self-invocation is not going to result
    in the advice associated with a method invocation getting a chance to execute.

  5. #5
    Join Date
    Jul 2007
    Posts
    101

    Default

    That might be clear to you as meaning the same thing, but I would not say that it is clear to most people.

    It would be really nice if the documentation called out specifically that you must use weaving if you are delegating to methods that are marked with @Transactional, since the advice will only be applied to methods on beans that are directly wrapped in a Spring proxy (ie. directly configured through Spring).

  6. #6
    Join Date
    Aug 2006
    Location
    Now Germany, previously Ukraine
    Posts
    1,546

    Default

    I guess you have somewhat misunderstand behavior.

    The problem is not with delegation as such, the problem is with calls inside same object. I.e. if you have in some object a method without transactional annotation and at this method is called outside of scope of existing transaction and this method delegates to another method of the same object marked with @Transactional then no proxy is comes into play and for this reason no transaction is started. If method marked with @Transactional resides in the some other object, then proxy is used and transaction would start.

    And documentation states exactly this - but in slightly more general terms, as this behavior is common for whole Spring AOP (or, really, any proxy-based AOP - spring or no Spring) and not only for @Transactional or transaction handling.

    BTW, in my opinion proxy-based AOP is to fragile as has to much restrictions, real AOP based on code weaving (AspectJ-based) is much more preferable.

    Regards,
    Oleksandr

    Quote Originally Posted by ccanning View Post
    That might be clear to you as meaning the same thing, but I would not say that it is clear to most people.

    It would be really nice if the documentation called out specifically that you must use weaving if you are delegating to methods that are marked with @Transactional, since the advice will only be applied to methods on beans that are directly wrapped in a Spring proxy (ie. directly configured through Spring).

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •