Reputation: 321
Question about @Transactional working in @Async working
This is a code sketch for an example:
@Async
@Transactional
public void data(List<Pass> pass) {
//code
for(City city : city) {
for(Dep dep: city.getDeps()) {
//code
setXor(user, xor);
//code
}
}
}
@Transactional
public void setXor(User user, Xor xor) {
//code
user.setXor(xor);
}
The question is, how will this work, does @Transactional extend from the data method to the setXor method (if you put an annotation on the data method, then maybe you don’t need to put it on setXor? And it will automatically switch to this method)
Also a question about @Async, will setXor work on a new thread along with Async? That is, there will be a main thread, a new one is created, which includes the data method, and since the data method called another method, it will be executed on the same thread as the data method, there will be no third thread. Or vice versa and the setXor method is executed in the main thread?
Upvotes: 13
Views: 28612
Reputation: 452
i was successful, only when i used jdbc template(this is so sad :() Note: in this case @Scheduled and @Async have the same result
@Configuration
@PropertySource("")
@EnableJpaRepositories(basePackages = "com.foo.myapp")
public class DataSourceConfig {
@Bean
public LocalContainerEntityManagerFactoryBean transpEntityManager() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
return em;
}
@Bean
@ConfigurationProperties(prefix = "app.datasource.transp")
public DataSourceProperties transpDataSourceProperties() {
return new DataSourceProperties();
}
@Bean(name = "datasource_transp")
public DataSource transpDataSource() {
return transpDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean(name = "tm_transp")
@Autowired
DataSourceTransactionManager tmTransp(@Qualifier("datasource_transp") DataSource datasource) {
DataSourceTransactionManager txm = new DataSourceTransactionManager(datasource);
return txm;
}
@Bean(name = "jdbcTemplateTransp")
public JdbcTemplate jdbcTemplateTransp(@Qualifier("datasource_transp") DataSource ds) {
return new JdbcTemplate(ds);
}
}
@Service
@EnableScheduling
public class ScheduledService {
@Autowired
private ReportDataService reportDataService;
@Autowired
private AsyncService async;
@Autowired
@Qualifier("movProcTPTE")
private TaskExecutor movProcTaskExecutor;
@Scheduled(fixedDelay = 1000 * 60,initialDelay = 60000)
public void agendamentoImportacaoMovProcessual(){
movProcTaskExecutor.execute(
() -> {
myService.methodWithDatabasePersist();
}
);
}
}
@Service
public class ReportDataService {
@Autowired
@Qualifier("jdbcTemplateTransp")
private JdbcTemplate jdbc;
public void jdbcSave(List<ReportData> list){
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime date = LocalDateTime.now();
String dateStr = date.format(fmt);
ReportData report = list.get(0);
String sql = "INSERT INTO .....";
jdbc.update(sql);
}
public void methodWithDatabasePersist(){
jdbcSave(relatorios);
}
}
Upvotes: 1
Reputation: 4038
As per Spring Transaction Documentation
All code within a transaction scope runs in that transaction. However, you can specify the behavior if a transactional method is run when a transaction context already exists. For example, code can continue running in the existing transaction (the common case), or the existing transaction can be suspended and a new transaction created.
@Transactional
commonly works with thread-bound transactions managed byPlatformTransactionManager
, exposing a transaction to all data access operations within the current execution thread. Note: This does not propagate to newly started threads within the method.
@Transactional
is powered by Aspect-Oriented Programming. Therefore, processing occurs when a bean is called from another bean. In the example above, the method is called from the same class so that no proxies can be applied.
When a method without @Transactional
is called within a transaction block, the parent transaction will continue to exist for the new method. It will use the same connection from the parent method (method with @Transactional) and any exception caused in the called method (method without @Transactional) will cause the transaction to rollback as configured in the transaction definition.
If the @Async
annotation is being used extra care should be taken with respect to transaction. When a @Transactional
Spring @Component
calls a method annotated with @Async
the call to the asynchronous method is being scheduled and executed at a later time by a task executor and is thus handled as a 'fresh' call, i.e. without a transactional context. If the @Async
method (or the @Component
in which it is declared) is not @Transactional
by itself Spring will not manage any needed transactions.
In order to make Spring manage the transaction of the @Async
method either the @Component
or the method itself should declare the @Transactional
annotation, this way Spring will manage the transaction even if a method is being executed asynchronous.
Upvotes: 16
Reputation: 457
Spring doesn't create transactions for calls in the same class so the setXor will be executed in the same Transaction as data no matter if you annotate it with transactional or not.
I think also setXor and data will be executed in one Thread other than the main.
Upvotes: 2