我想在我的应用程序的开头读取文本数据夹具(CSV文件)并将其放入我的数据库中。
为此,我使用初始化方法( @PostConstruct 注释)创建了 PopulationService 。
我也希望它们在一次交易中执行,因此我在同一方法上添加了 @Transactional 。
然而, @Transactional 似乎被忽略了: 在我的低级DAO方法中启动/停止事务。
我是否需要手动管理交易呢?
答案 0 :(得分:78)
在@PostConstruct中(与InitializingBean接口中的afterPropertiesSet一样),无法确保所有后期处理都已完成,因此(实际上)可能没有事务。确保其正常工作的唯一方法是使用TransactionTemplate。
因此,如果您希望在@PostConstruct
内执行某项内容,您必须执行以下操作:
@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
}
});
}
}
答案 1 :(得分:15)
我认为@PostConstruct
只能确保完成当前类的预处理/注入。这并不意味着整个应用程序上下文的初始化已经完成。
但是,您可以使用spring事件系统在应用程序上下文的初始化完成时接收事件:
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
// do startup code ..
}
}
有关详细信息,请参阅文档部分Standard and Custom Events。
答案 2 :(得分:2)
@Platon Serbin 的回答对我不起作用。所以我一直在寻找并找到以下答案来挽救我的生命。 :d
答案在这里No Session Hibernate in @PostConstruct,我冒昧地转录:
@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;
}
});
}
答案 3 :(得分:2)
作为更新,从Spring 4.2开始,@EventListener
批注允许更简洁的实现:
@Service
public class InitService {
@Autowired
MyDAO myDAO;
@EventListener(ContextRefreshedEvent.class)
public void onApplicationEvent(ContextRefreshedEvent event) {
event.getApplicationContext().getBean(InitService.class).initialize();
}
@Transactional
public void initialize() {
// use the DAO
}
}
答案 4 :(得分:0)
在transactionOperations.execute()
或@PostConstruct
方法中使用@NoTransaction
都可以正常工作
@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 {
}
}
答案 5 :(得分:0)
注入self并通过其调用@Transactional
方法
public class AccountService {
@Autowired
private AccountService self;
@Transactional
public void resetAllAccounts(){
//...
}
@PostConstruct
private void init(){
self.resetAllAccounts();
}
}
对于不支持自我注入的较早的Spring版本,注入BeanFactory
并以self
的形式获取beanFactory.getBean(AccountService.class)
答案 6 :(得分:0)
spring 的事务部分可能没有在 @PostConstruct
处完全初始化。
使用 ContextRefreshedEvent
事件的侦听器来确保交易可用:
@Component
public class YourService
implements ApplicationListener<ContextRefreshedEvent> // <= ensure correct timing!
{
private final YourRepo repo;
public YourService (YourRepo repo) {this.repo = repo;}
@Transactional // <= ensure transaction!
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
repo.doSomethingWithinTransaction();
}
}