0

I am writing Spring Boot application using Spring Data repositories. I have method that resets database and fills it with sample data. It works, however Spring uses hundreds of transactions to do this. Is there any way to limit number of transactions created by repositories to 1 or to not use them at all? I would like to reuse same transaction within fillApples and fillBananas methods. I've tried using different combinations of @Transactional(propagation = Propagation.SUPPORTS) but it does not change anything.

interface AppleRepository extends CrudRepository<Apple, Long>
interface BananaRepository extends JpaRepository<Banana, Long>

@Service
public class FruitService{

  @Autowired
  private final AppleRepository appleRepository;
  @Autowired
  private final BananaRepository bananaRepository;

  public void reset(){
    clearDb();
    fillApples();
    fillBananas();
    //more fill methods
  }

  private void clearDb(){
    appleRepository.deleteAll();
    bananaRepository.deleteAll();
  }

  private void fillApples(){
      for(int i = 0; i < n; i++){
        Apple apple = new Apple(...);
        appleRepository.save(apple);
      }
  }

  private void fillBananas(){
      for(int i = 0; i < n; i++){
        Banana banana = new Banana(...);
        bananaRepository.save(banana);
      }
  }

}


@RestController
public class FruitController{

  @Autowired
  private FruitService fruitService;

  @RequestMapping(...)
  public void reset(){
      fruitService.reset();
  }

}
Infinity
  • 3,431
  • 3
  • 25
  • 46
  • where did you add the @Transactional annotation ? – benbenw Nov 26 '15 at 21:45
  • I've annotated reset method with `@Transactional` and rest of methods with `@Transactional(propagation = SUPPORTS)`. I know that `@Transactional` does not work with private methods, but making them public didn't change anything. – Infinity Nov 26 '15 at 21:47
  • You need to annotate reset function with Transactional Required. I think your repo classes has Transactional annotation on class level or per function so calls to methods open trx since there is no existing. – hsnkhrmn Nov 26 '15 at 21:53
  • 2
    the pb is not only with private / public but who call the method. Calling a transactionnal annotated method within the same bean (self-invocation) will not go through the spring transaction management ( in proxy mode which is the default) see http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#transaction-declarative-annotations – benbenw Nov 26 '15 at 21:58
  • did you add the @EnableTransactionManagement when testing the @ Transactional on the reset method? – benbenw Nov 26 '15 at 22:01
  • for the private public discussion have a look at this answer: http://stackoverflow.com/a/4396530/280244 – Ralph Nov 26 '15 at 22:05
  • @benbenw, yes I did, thank you for response – Infinity Nov 27 '15 at 19:49

1 Answers1

2

You have to annotate your reset() method with @Transaction and a propagation configuration that makes sure that the method runs in an transaction (create or reuse the existing annotation - for example Propagation REQUIRED (that the default for @Transactional))

Your code has no @Transactional but in your comment you wrote that you have one, but you use the "wrong" Propagation = SUPPORTS. Because the meaning of SUPPORTS is:

SUPPORTS Support a current transaction, execute non-transactionally if none exists.

So you will not create a new transaction if there is none (@Transactional(propagation = SUPPORTS) will never do any thing, it mean just do nothing with the transaction)

So you have to use@Transactional(propagation = REQUIRED)

@Transactional(propagation = REQUIRED)
public void reset(){
    clearDb();
    fillApples();
    fillBananas();
    //more fill methods
  }

@see: Propagation java doc

Ralph
  • 118,862
  • 56
  • 287
  • 383