2013-04-24 69 views
4

這個問題的核心是:是否有可能從Spring關機掛鉤觸發的方法執行交易?@Transactional在春季關機正常關機Hsqldb

目前我在這個問題發現,實現SmartLifeCycle一個HyperSqlDbServer類: In a spring bean is it possible to have a shutdown method which can use transactions?

我有一個標記事務那類被調用作爲停止方法的一部分的方法:

@Transactional 
public void executeShutdown() { 
    hsqlDBShutdownService.executeShutdownQuery(); 
    hsqlDBShutdownService.closeEntityManager(); 
} 

在該方法中使用的服務是一個黑客一點,我不得不這樣做,因爲我不能在EntityManager的自動裝配這個類:

@Service 
public class HsqlDBShutdownService { 

    @PersistenceContext 
    private EntityManager entityManager; 

    @Autowired 
    private HyperSqlDbServer hyperSqlDbServer; 

    @Transactional 
    public void executeShutdownQuery() { 
     entityManager.createNativeQuery("SHUTDOWN").executeUpdate(); 
    } 

    @Transactional 
    public void closeEntityManager() { 
     entityManager.close(); 
    } 

    @PostConstruct 
    public void setHsqlDBShutdownService() { 
     hyperSqlDbServer.setShutdownService(this); 
    } 
} 

您可能會注意到,我真正想要完成的是在停止服務器之前調用查詢「SHUTDOWN」。如果沒有這個,hsqldb鎖定文件會在服務器重新啓動時出現,並且服務器會引發異常。

上面的代碼會產生以下異常:

javax.persistence.TransactionRequiredException: Executing an update/delete query 
    at org.hibernate.ejb.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:96) 
     ... 

所以我原來的問題表示,但如果有人對我怎麼能執行這個查詢另一種方式一個想法,我會嘗試爲好。

僅供參考,我也試過@PreDestroy註釋,但得到相同的TransactionRequiredException。

編輯:爲了完整起見,我使用的是JpaTransactionManager接口和整個我的項目@Transactional註釋工作,除了在關機...

編輯2:數據源和事務管理器配置:

@Configuration 
@EnableTransactionManagement 
@PropertySource("classpath:persistence.properties") 
public class PersistenceConfig implements TransactionManagementConfigurer { 

    private static final String PASSWORD_PROPERTY = "dataSource.password"; 
    private static final String USERNAME_PROPERTY = "dataSource.username"; 
    private static final String URL_PROPERTY = "dataSource.url"; 
    private static final String DRIVER_CLASS_NAME_PROPERTY = "dataSource.driverClassName"; 

    @Autowired 
    private Environment env; 

    @Bean 
    @DependsOn("hsqlDb") 
    public DataSource configureDataSource() { 
     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     dataSource.setDriverClassName(env.getProperty(DRIVER_CLASS_NAME_PROPERTY)); 
     dataSource.setUrl(env.getProperty(URL_PROPERTY)); 
     dataSource.setUsername(env.getProperty(USERNAME_PROPERTY)); 
     dataSource.setPassword(env.getProperty(PASSWORD_PROPERTY)); 
     return dataSource; 
    } 

    @Bean 
    @DependsOn("hsqlDb") 
    public LocalContainerEntityManagerFactoryBean configureEntityManagerFactory() { 
     LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); 
     entityManagerFactoryBean.setDataSource(configureDataSource()); 
     entityManagerFactoryBean.setPackagesToScan("com.mycompany.model.db"); 
     entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); 

     Properties jpaProperties = new Properties(); 
     jpaProperties.put(org.hibernate.cfg.Environment.DIALECT, env.getProperty(org.hibernate.cfg.Environment.DIALECT)); 
     jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_AUTO, env.getProperty(org.hibernate.cfg.Environment.HBM2DDL_AUTO)); 
     jpaProperties.put(org.hibernate.cfg.Environment.SHOW_SQL, env.getProperty(org.hibernate.cfg.Environment.SHOW_SQL)); 
     jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR, env.getProperty(org.hibernate.cfg.Environment.HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR)); 
     jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_IMPORT_FILES, env.getProperty(org.hibernate.cfg.Environment.HBM2DDL_IMPORT_FILES)); 
     entityManagerFactoryBean.setJpaProperties(jpaProperties); 

     return entityManagerFactoryBean; 
    } 

    @Override 
    @Bean() 
    @DependsOn("hsqlDb") 
    public PlatformTransactionManager annotationDrivenTransactionManager() { 
     return new JpaTransactionManager(); 
    } 

} 
+0

嘗試調試該行並查看「HsqlDBShutdownService」實例的對象類型。它應該被代理。如果不是,你的'@ Transactional'不起作用。 – 2013-04-24 23:40:09

+0

調試顯示該對象上沒有代理服務器。所以我想,結合原始TransactionRequiredException確認註釋不起作用。那麼,作爲智能生命週期停止方法的一部分,執行交易是不可能的? – mag382 2013-04-25 13:59:04

+0

@ mag32就是這樣。如果您使用交易管理器配置更新您的問題,我們可以仔細查看。 – 2013-04-25 13:59:51

回答

1

我發現了一個關閉HsqlDB數據庫的解決方法,但它涉及避免使用Spring的EntityManager和@Transactional,因爲它們在服務器關閉期間顯然不工作。下面是我修改的HsqlDBShutdownService。關鍵在於不是使用EntityManager來調用查詢,而是手動創建一個新的jdbc連接,並以這種方式調用查詢。這就避免了對需求@Transactional:

@Service 
public class HsqlDBShutdownService { 

    @Autowired 
    private ApplicationContext applicationContext; 

    @PersistenceContext 
    private EntityManager entityManager; 

    @Autowired 
    private HyperSqlDbServer hyperSqlDbServer; 

    public void executeShutdownQuery() { 

     Connection conn = null; 
     try { 
      JdbcTemplate jdbcTemplate = new JdbcTemplate(this.applicationContext.getBean(DataSource.class)); 
      conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource()); 
      conn.setAutoCommit(true); 
      jdbcTemplate.execute("SHUTDOWN"); 
     } catch(Exception ex) { 
      ex.printStackTrace(); 
     } finally { 
      try { 
       if(conn != null) 
        conn.close(); 
      } catch(Exception ex) { 
       ex.printStackTrace(); 
      } 
     } 
    } 

    @Transactional 
    public void closeEntityManager() { 
     entityManager.close(); 
    } 

    @PostConstruct 
    public void setHsqlDBShutdownService() { 
     hyperSqlDbServer.setShutdownService(this); 
    } 

} 

服務器現在可以成功地重新啓動而沒有圍繞HSQLDB留下鎖定文件。