1 minute read

There’s a very common gotcha with Spring annotations, it’s caught me out in the past, and is certainly one of the things that I check when reviewing pull requests. Have a look at this example.

public class MySpringService {

  public void doSomething(){
    // do some stuff, then update the DB
    updateDb();
  }
  
  @Transactional
  public void updateDb(){
    // update the db with something
  }
  
}

We have 2 methods in the same class, one calls another. Whilst this looks fine to the untrained eye, the @Transactional will be ignored, since the method is called directly from the same class. By making a direct call, we bypass the Spring IoC, so it doesn’t have a chance to intercept and run the annotations.

To solve this, we can move the updateDb out into it’s own class, so the call would be managed by Spring and it can make use of the annotation, like so.

@Component
public class MySpringService {

  @Autowired
  private MyDbService myDbService;
  
  public void doSomething(){
    // do some stuff, then update the DB
    myDbService.updateDb();
  }

}

@Component
public class MyDbService{

  @Transactional
  public void updateDb(){
    // update the db with something
  }
  
}

I’ve used the example of @Transactional as it’s easy to understand, but the same would apply to other annotation types.