Announcement Announcement Module
Collapse
No announcement yet.
Testing and Transactional Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Testing and Transactional

    I'm new to Spring and having a difficult time figuring out @Transactional. My basic setup:

    JPA, Java Configuration, CTW, AnnotationTransactionAspect.aspectOf(), spring-configured, Hibernate, component scan on everything for now.

    Test runs with SpringJUnit4ClassRunner. Each Test class is annotated with:

    Code:
    @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD )
    I have a parent entity and a child entity. There is a ONETOMANY relationship between them. Though I don't think this is relevant.

    My test methods are NOT annotated with @Transactional. I want to make sure that my service layer is using flush, et al correctly so I need committed transactions between operations within the test method.

    My @Transactional usage is in my service layer. Furthermore, the service layer is injected into a fluent interface that the test uses. This allows me to do things like this:

    Code:
         ParentOperations.id( parent.getId() ).getChildrenNames();
    Here's a brief version of ParentOperations:

    Code:
        @Configurable
        public class ParentOperations {
           @AutoWired
           private ParentService service;
           private Parent parent;
    
           public static ParentOperations id( Long id ) {
              ParentOperations ops = new ParentOperations();
              ops.parent = ops.service.findById( id );
              return ops;
           }
    
           public Set<Child> getChildren() {
              return service.getChildrenOf( this.parent );
           }
        }
    There's a bunch more to it but you get the idea. All the methods in ParentService are @Transactional. The #getChildrenOf method simply populates a HashSet using the result of parent.getChildren() which is using a LAZY fetch but should be fine since it is done within a transaction.

    So here's the rub. In my test method, if I persist the parent first and then do a ParentOperations.id( parent.getId() ).getChildren() I get an exception in ParentService#getChildrenOf when trying to build the Set of children with Spring saying that during the lazy load that there is "no session or session has been closed".

    In the logging I can see that Spring "found a thread-bound entity manager" and is "participating in the current transaction." But I can see after the #persist call that the EntityManager has been closed.

    As you might imagine if I annotate the WHOLE test method all is well. But if I do that I cannot ensure that stuff is really happening correctly in the database verses just the cache using object references.

    How can I have an active transaction here but no session?

    Appreciate any pointers.

  • #2
    Okay, I've got this narrowed down further. If in my service I have these methods (all transactional):

    Code:
       public Parent findById( Long id );
       public Set<Child> getChildrenOf( Parent parent );
    And I have another method in this service that uses the two methods above as in:

    Code:
        public Set<Child> getChildrenOf( Long id ) {
           Parent parent = findById( id );
           return getChildrenOf( parent );
        }
    Then in client code, I can call that method and it works. But if I try to call #findById and then #getChildrenOf I get the "no session for transaction" exception. But if my service has a method that calls them together it works fine.

    Can anyone simply explain this to me? In my client code both methods are called on the same instance of my service.

    TIA

    Comment

    Working...
    X