Search code examples
javaspringspring-boottransactionsspring-transactions

@Transactional only on one method


I need to make a @Scheduled method that has a list of schemas and for each schema, deletes rows from 2 tables.

    @Scheduled(fixedDelay = 10000)
public void scheduleFixedDelayTask() {
    List<String> presentSchemas = getPresentSchemas();
    for (String schema : presentSchemas) {
        deleteFromCustomerTables(schema);
    }
}

I've defined deleteFromCustomerTables as @Transactional(propagation = Propagation.REQUIRES_NEW) and inside it i use the EntityManager to delete rows from 2 tables.

In order to make it work i need to add @Transactional to scheduleFixedDelayTask, otherwise i recive a TransactionRequiredException.

My problem is that i do not want the whole scheduler to be @Transactional, if something goes wrong in one schema i do not want to do a rollback of all schemas.

I've also tried without @Transactional and with :

    Session session = entityManager.unwrap(Session.class);
    Transaction t = session.beginTransaction();
    //exec delete
    t.commit();
    session.close();

But i still recieve TransactionRequiredException. Do you have a solution?


Solution

    • You have to be sure that you configured the transaction manager something like this:
    @Configuration
    @EnableTransactionManagement
    public class TransactionConfig {
    
      @Bean
      @Primary
      public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager();
      }
    }
    
    • You have to be sure that method deleteFromCustomerTables is not in the same component, something like this:
    @Component
    class Component1 {
       void scheduleFixedDelayTask(){...}
    }
    
    @Component
    class Component2 {
       void deleteFromCustomerTables(){...}
    }
     
    

    But at a very high level, Spring creates proxies for classes that declare @Transactional on the class itself or on members. The proxy is mostly invisible at runtime. It provides a way for Spring to inject behaviors before, after, or around method calls into the object being proxied. Transaction management is just one example of the behaviors that can be hooked in. Security checks are another. And you can provide your own, too, for things like logging. So when you annotate a method with @Transactional, Spring dynamically creates a proxy that implements the same interface(s) as the class you're annotating. And when clients make calls into your object, the calls are intercepted and the behaviors injected via the proxy mechanism.