I have an erp application in: spring mvc, hibernate and postgresql, with multitenancy approach (schema by tenant). A task is being created for the automatic sending of the receipts generated during the day by the tenants, for this we are using spring Scheduling, but when the scheduled task is executed, the error occurs: Could not open Hibernate Session for transaction. Here I share with you the configuration and part of the code of Scheduled.
- configuring hibernate with spring for transaction handling.
@Configuration
@PropertySource("classpath:hibernate.properties")
@EnableTransactionManagement
public class AppContext {
@Autowired
private Environment environment;
@Autowired
private MultiTenantConnectionProvider multiTenantConnectionProvider;
@Autowired
private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] {"Entity"});
sessionFactory.setHibernateProperties(hibernateProperties());
sessionFactory.setCurrentTenantIdentifierResolver(currentTenantIdentifierResolver);
sessionFactory.setMultiTenantConnectionProvider(multiTenantConnectionProvider);
return sessionFactory;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("hibernate.connection.driver_class"));
dataSource.setUrl(environment.getRequiredProperty("hibernate.connection.url"));
dataSource.setUsername(environment.getRequiredProperty("hibernate.connection.username"));
dataSource.setPassword(environment.getRequiredProperty("hibernate.connection.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
properties.put("hibernate.multiTenancy", environment.getRequiredProperty("hibernate.multiTenancy"));
return properties;
}
@Bean
public HibernateTransactionManager getTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
}
- here is my class that starts on cron.
@Component
public class CronSUNAT {
public final String EVERY_DAY_AT_11_PM = "0 0 23 * * ?";
private static final Logger LOGGER = LoggerFactory.getLogger(CronSUNAT.class);
@Autowired
public ITaskManager taskManager;
@Scheduled(cron = EVERY_DAY_AT_11_PM)
public void cronVouchers() {
taskManager.sendVouchersToSunat();
}
@Scheduled(cron = EVERY_DAY_AT_11_PM)
public void cronRemissionGuide() {
taskManager.sendRemissionGuidesToSunat();
}
}
- class TaskManager.
@Service
public class TaskManager extends BasicTaskManager implements ITaskManager {
private final Logger LOGGER = LoggerFactory.getLogger(TaskManager.class);
static final String DEFAULT_TENANT = "public";
public TenantServiceI tenantService;
public IBillingService billingService;
public TaskManager(TenantServiceI tenantService,IBillingService billingService) {
this.tenantService = tenantService;
this.billingService = billingService;
}
@Override
@Transactional
public void sendVouchersToSunat() {
try {
LOGGER.info("IN CLASS TASK MANAGER :: SEND VOUCHERS TO SUNAT");
List<TenantDTO> tenants = tenantService.getAllTenants();
if (!tenants.isEmpty()) {
for (TenantDTO tenant : tenants) {
TenantContext.setTenantId(tenant.getIdentifier());
continueSendVouchersToSunat();
}
}
continueSendVouchersToSunat();
} catch (Exception e) {
LOGGER.info("Ocurrio un error => " + e.getMessage());
}
}
@Override
public void sendRemissionGuidesToSunat() {
try {
List<TenantDTO> tenants = tenantService.getAllTenants();
if (!tenants.isEmpty()) {
for (TenantDTO tenant : tenants) {
TenantContext.setTenantId(tenant.getIdentifier());
continueSendRemissionGuidesToSunat();
}
}
continueSendRemissionGuidesToSunat();
} catch (Exception e) {
// TODO: handle exception
}
}
}
I tried putting the @Transactional annotation to the sendVoucherToSunat method, but I got the same result. Thank you for your help.