spring - transacciones - @Transactional en el método @PostConstruct
transacciones con spring framework (5)
Creo que @PostConstruct
solo garantiza que el preprocesamiento / inyección de tu clase actual haya finalizado. No significa que la inicialización de todo el contexto de la aplicación haya finalizado.
Sin embargo, puede usar el sistema de eventos de primavera para recibir un evento cuando finaliza la inicialización del contexto de la aplicación:
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
// do startup code ..
}
}
Consulte la sección de documentación Eventos estándar y personalizados para obtener más detalles.
Quiero leer los accesorios de datos de texto (archivos CSV) al inicio de mi aplicación y ponerlos en mi base de datos.
Para eso, he creado un PopulationService con un método de inicialización ( @PostConstruct anotación).
También quiero que se ejecuten en una sola transacción, y por lo tanto, agregué @Transactional en el mismo método.
Sin embargo, el @Transactional parece ser ignorado: la transacción se inicia / detiene en mis métodos DAO de bajo nivel.
¿Debo administrar la transacción manualmente?
El uso de transactionOperations.execute()
en @PostConstruct
o en el método @NoTransaction
funciona
@Service
public class ConfigurationService implements ApplicationContextAware {
private static final Logger LOG = LoggerFactory.getLogger(ConfigurationService.class);
private ConfigDAO dao;
private TransactionOperations transactionOperations;
@Autowired
public void setTransactionOperations(TransactionOperations transactionOperations) {
this.transactionOperations = transactionOperations;
}
@Autowired
public void setConfigurationDAO(ConfigDAO dao) {
this.dao = dao;
}
@PostConstruct
public void postConstruct() {
try { transactionOperations.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(final TransactionStatus status) {
ResultSet<Config> configs = dao.queryAll();
}
});
}
catch (Exception ex)
{
LOG.trace(ex.getMessage(), ex);
}
}
@NoTransaction
public void saveConfiguration(final Configuration configuration, final boolean applicationSpecific) {
String name = configuration.getName();
Configuration original = transactionOperations.execute((TransactionCallback<Configuration>) status ->
getConfiguration(configuration.getName(), applicationSpecific, null));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
}
Inyectarse y llamar a través del @Transactional
método @Transactional
public class AccountService {
@Autowired
private AccountService self;
@Transactional
public void resetAllAccounts(){
//...
}
@PostConstruct
private void init(){
self.resetAllAccounts();
}
}
Para versiones anteriores de Spring que no admiten la autoinyección, inyecte BeanFactory
y obtenga self
como beanFactory.getBean(AccountService.class)
La respuesta de @Platon Serbin no funcionó para mí. Así que seguí buscando y encontré la siguiente respuesta que me salvó la vida. :RE
La respuesta es aquí No Session Hibernate en @PostConstruct , que me tomé la libertad de transcribir:
@Service("myService")
@Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
@Autowired
private MyDao myDao;
private CacheList cacheList;
@Autowired
public void MyServiceImpl(PlatformTransactionManager transactionManager) {
this.cacheList = (CacheList) new TransactionTemplate(transactionManager).execute(new TransactionCallback(){
@Override
public Object doInTransaction(TransactionStatus transactionStatus) {
CacheList cacheList = new CacheList();
cacheList.reloadCache(MyServiceImpl.this.myDao.getAllFromServer());
return cacheList;
}
});
}
esto podría ser útil ( http://forum.springsource.org/showthread.php?58337-No-transaction-in-transactional-service-called-from-PostConstruct ):
En @PostConstruct (como con afterPropertiesSet desde la interfaz InitializingBean) no hay forma de garantizar que todo el procesamiento posterior ya esté hecho, por lo que (de hecho) no puede haber Transacciones. La única manera de asegurarse de que eso funcione es mediante el uso de una TransactionTemplate.
Entonces, si desea que se @PostConstruct
algo en su @PostConstruct
dentro de la transacción, debe hacer algo como esto:
@Service("something")
public class Something {
@Autowired
@Qualifier("transactionManager")
protected PlatformTransactionManager txManager;
@PostConstruct
private void init(){
TransactionTemplate tmpl = new TransactionTemplate(txManager);
tmpl.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
//PUT YOUR CALL TO SERVICE HERE
}
});
}
}