3

I'm using the @Transactional annotation on a seam component similar to:

@Name( "myComponent" )
@AutoCreate
public class MyComponent
{
    public void something() {
        ...
        doWork();
    }
    ...
    @Transactional
    protected void doWork() {
        try {
            log.debug( "transaction active: " + Transaction.instance().isActive() );
        } catch (Exception ignore) {}

        // some more stuff here that doesn't appear to be inside a transaction
    }
}

In the "some more stuff" section, I'm modifying some Hibernate entities and then had a bug where an Exception was thrown. I noticed that the Exception wasn't causing the transaction to be rolled back (the modified entities were still modified in the db) so I added the "transaction active" logging. When this code executes, isActive() returns false.

Is there something I'm missing? Why isn't the transaction active?

In case it matters, I'm using the Seam component from inside another component that is using RESTEasy annotations to trigger my method calls.

Taryn
  • 242,637
  • 56
  • 362
  • 405
Chris Williams
  • 11,647
  • 15
  • 60
  • 97

1 Answers1

6

I'm not familiar with how Seam works so my apologies in advance if this answer does not apply.

I noticed that the method that is @Transactional is protected. This implies to me that it is being called by another internal method.

With Spring's AOP, you mark the public methods with @Transactional which are wrapped and replaced with a transaction proxy. When an external class calls the public method, it is calling the proxy which forms the transaction. If the external class calls another public method that is not marked with @Transactional which then calls an internal method which is, there will be no transaction created because the proxy is not being called at all.

In Spring, even if you change your doWork() method to be public, the same problem would happen. No transaction because the proxy object is not being called. Method calls made inside of the class are not making calls to the proxy object.

A quick read of some documentation seems to indicate that, like Spring AOP, Seam is using CGLib proxying. The question is if it is able to proxy all methods -- even if they are called from within the proxied object. Sorry for wasting your time if this answer does not apply.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • Possibly related to http://stackoverflow.com/questions/3401821/weld-injection-failing-when-calling-a-method-from-an-super-abstract-class-with-w – Gray Oct 27 '11 at 14:04
  • I think you are on to something here – Shervin Asgari Oct 31 '11 at 15:49
  • 2
    Accepting this because his it's really close to what the problem turned out to be for us with Seam. The @Transactional annotation isn't used unless you go from one Seam component to another. In this case, we were calling our Transactional method from within the same Seam component (MyComponent). By pulling the call to the Transactional method out to another component, the TransactionInterceptor is now getting triggered and all is good. – Chris Williams Nov 01 '11 at 20:02
  • Yeah, I thought it was something like that. Glad it helped. – Gray Nov 01 '11 at 20:11