Reputation: 51
@Transactional annotation on a method inside the Application class is not rolling back insertions. However, @Transactional annotation on the service class(EmpService.java) method("insertEmp(Emp emp)") is working as expected.
Could someone please let me know why @Transactional working differently? Spring Boot version - 2.1.3.RELEASE with the h2 database. Please let me know if any additional information required.
@SpringBootApplication
@ComponentScan("org.saheb")
@EnableJpaRepositories("org.saheb.repo")
@EntityScan("org.saheb.vo")
@EnableTransactionManagement
public class SpringJpaTransactionApplication implements CommandLineRunner {
@Autowired
private EmpService empService;
public static void main(String[] args) {
SpringApplication.run(SpringJpaTransactionApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
insertSingleBatch();
}
@Transactional(rollbackFor=RuntimeException.class, propagation=Propagation.REQUIRES_NEW)
public void insertSingleBatch() {
try {
Set<Emp> empSet = new LinkedHashSet<>();
Dept dept = new Dept();
dept.setDeptNo(10);
empSet.add(new Emp("abc", "abc", dept));
empSet.add(new Emp("xyz", "xyz", dept));
empSet.add(new Emp("def", "def", dept));
empSet.add(new Emp("pqrstu", "pqr", dept));// This will fail as max character allowed in 5 and should rollback all the insertion. But, first three records are getting saved in h2 database.
empService.insertEmp(empSet);
} catch (RuntimeException e) {
System.out.println("Exception in batch1.." + e.getMessage());
}
}
}
@Service
public class EmpService {
@Autowired
private EmpRepository empRepository;
//@Transactional(rollbackFor=RuntimeException.class, propagation=Propagation.REQUIRES_NEW)//This is working as expected as all the insertions are rolling back after failure of 4th insertion
public void insertEmp(Set<Emp> empSet) {
System.out.println("Inside insert");
for (Emp temp : empSet) {
Emp temp2 =empRepository.save(temp);
System.out.println("inserted-->"+temp2.getFirstName());
}
}
}
Upvotes: 0
Views: 1160
Reputation: 90447
You are "self-invocation" a @Transactional
method from the same bean which will not work .This behaviour is well explained in the docs at here and here (Search the keyword "self-invocation")
You can simply move the @Transactional
method to another bean.Then inject this bean to its client bean and invoke this @Transactional
method.
Or use the TransactionTemplate
to execute it within a transaction:
@Autowired
private TransactionTemplate txTemplate;
@Override
public void run(String... args) throws Exception {
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(status->{
insertSingleBatch();
return null;
});
}
Please note that TransactionTemplate
will ignore the setting on the @Transactional
and you have to configure it programatically.
Upvotes: 3