web-dev-qa-db-ja.com

@PostConstructメソッドの@Transactional

アプリケーションの開始時にテキストデータフィクスチャ(CSVファイル)を読み取り、データベースに配置したい。

そのために、初期化メソッドでPopulationServiceを作成しました(@ PostConstructアノテーション)。

また、それらを単一のトランザクションで実行したいので、同じメソッドに@ Transactionalを追加しました。

ただし、@ Transactionalは無視されるようです。トランザクションは、低レベルのDAOメソッドで開始/停止されます。

トランザクションを手動で管理する必要がありますか?

40
Raphael Jolivet

これは役に立つかもしれません( http://forum.springsource.org/showthread.php?58337-No-transaction-in-transactional-service-called-from-PostConstruct ):

(InitializingBeanインターフェースのafterPropertiesSetのように)@PostConstructには、すべての後処理が既に行われていることを保証する方法がないため、(実際には)トランザクションは存在できません。それが機能していることを確認する唯一の方法は、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
            }
        });
   }
}
83
Platon

おもう @PostConstructは、現在のクラスの前処理/インジェクションのみが終了することを保証します。アプリケーションコンテキスト全体の初期化が終了したことを意味するものではありません。

ただし、春のイベントシステムを使用して、アプリケーションコンテキストの初期化が終了したときにイベントを受信できます。

public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
  public void onApplicationEvent(ContextRefreshedEvent event) {
    // do startup code ..
  }    
}

詳細については、ドキュメントのセクション 標準およびカスタムイベント を参照してください。

15
micha

更新として、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
    }

}

3
DBE

@ Platon Serbinの答えは私にはうまくいきませんでした。だから私は検索を続け、私の命を救った次の答えを見つけました。 :D

答えはここにあります @ PostConstructにSession Hibernateはありません 、私は自由に書き起こしました:

@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;
        }

    });
}
2
carolnogueira

Selfを注入し、それを通して_@Transactional_メソッドを呼び出します

_public class AccountService {

    @Autowired
    private AccountService self;

    @Transactional
    public void resetAllAccounts(){
        //... 
    }

    @PostConstruct
    private void init(){
        self.resetAllAccounts();
    }

}
_

自己注入をサポートしない古いSpringバージョンの場合、BeanFactoryを注入し、selfbeanFactory.getBean(AccountService.class)として取得します

0
igor.zh

_@PostConstruct_または_@NoTransaction_メソッドでtransactionOperations.execute()を使用すると両方が機能します

_@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 {

    }
}
_
0
ikarayel