【问题标题】:@Transactional on Spring shutdown to properly shutdown Hsqldb@Transactional on Spring shutdown 正确关闭 Hsqldb
【发布时间】:2013-04-18 13:51:38
【问题描述】:

这个问题的核心是:是否可以从由 Spring 关闭挂钩触发的方法执行事务?

目前我有一个实现 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();
    }

}

【问题讨论】:

  • 尝试调试该行并查看 HsqlDBShutdownService 实例的 Object 类型。它应该被代理。如果不是,则您的 @Transactional 无法正常工作。
  • 调试显示该对象上没有代理。所以我猜想,结合原来的 TransactionRequiredException 确认注释不起作用。那么作为 SmartLifecycle 的停止方法的一部分执行事务是不可能的吗?
  • @mag32 就是这样。如果您使用事务管理器配置更新您的问题,我们可以仔细查看。
  • 好的上传。此外,在调试中,HsqlDBShutdownService 没有被代理,但在它的 executeShutdownQuery 方法中,EntityManger 被代理。
  • 您没有@ComponentScan 注释。您必须扫描包含您的@Components 的软件包,即。 @Service。此外,您的 TransactionManager 应该引用您的 DataSourceEntityManager(不确定是哪个),以便它可以开始和结束事务。

标签: spring hsqldb shutdown transactional


【解决方案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 锁定文件。

【讨论】:

    猜你喜欢
    • 2015-08-19
    • 1970-01-01
    • 2015-02-23
    • 2018-06-04
    • 2014-07-25
    • 1970-01-01
    • 2016-10-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多