@Transactional @PostConstruct方法

时间:2013-06-27 15:01:01

标签: spring transactions

我想在我的应用程序的开头读取文本数据夹具(CSV文件)并将其放入我的数据库中。

为此,我使用初始化方法( @PostConstruct 注释)创建了 PopulationService

我也希望它们在一次交易中执行,因此我在同一方法上添加了 @Transactional

然而, @Transactional 似乎被忽略了: 在我的低级DAO方法中启动/停止事务。

我是否需要手动管理交易呢?

7 个答案:

答案 0 :(得分:78)

这可能会有所帮助(http://forum.springsource.org/showthread.php?58337-No-transaction-in-transactional-service-called-from-PostConstruct):

  

在@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();
    }
}