2013-04-24 2 views
4

Сердце этого вопроса: возможно ли выполнить транзакцию с помощью метода, инициированного крюком отключения Spring?@Transactional при выключении пружины для правильного выключения Hsqldb

На данный момент у меня есть класс HyperSqlDbServer, который реализует SmartLifeCycle, как найти в этом вопросе: In a spring bean is it possible to have a shutdown method which can use transactions?

У меня есть метод в этом классе, который отмечен транзакционный, которая вызывается как часть методы остановки:

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

служба, используемая в этом методе является немного рубить, что я должен был сделать, потому что я не мог autowire в 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) 
     ... 

Так что мой первоначальный вопрос стоит, но если кто-нибудь есть мысли о том, как я мог бы выполнить этот запрос еще один способ, которым я постараюсь, что хорошо.

FYI, я также пробовал аннотацию @PreDestroy, но получаю такое же TransactionRequiredException.

Edit: Для полноты, я использую JpaTransactionManager и @Transactional аннотаций работать на протяжении всего моего проекта, за исключением остановки ...

Edit 2: Datasource и менеджер транзакций конфигурации:

@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' не работает. –

+0

Отладка не показывает прокси-сервера на этом объекте. Поэтому я предполагаю, что в сочетании с оригинальным TransactionRequiredException подтверждается, что аннотация не работает. Так что просто невозможно выполнить транзакцию как часть метода остановки SmartLifecycle? – mag382

+0

@ mag32 Вот и все. Если вы обновите свой вопрос с помощью конфигурации менеджера транзакций, мы можем поближе рассмотреть его. –

ответ

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 блокировки файлов вокруг.