【发布时间】:2014-08-20 21:29:41
【问题描述】:
(编辑:我已经为这个问题添加了一个赏金。我找到了一个解决方法(作为答案发布在下面),但我希望有人能解释为什么首先需要解决这个问题。)
我有一个在开发过程中连接到 Derby 数据库的 Spring webapp。这在我第一次运行 web 应用程序时工作正常,但在随后的运行中它在启动过程中失败,并出现“另一个 Derby 实例可能已经启动了数据库”SQLException。
我知道这是因为当我关闭 Tomcat 时与 Derby 的连接没有关闭,即使我希望 Spring 会自动处理它。所以我的问题是,如何正确断开与 Derby 的连接?不仅在手动停止 Tomcat 期间,而且在热部署新的 .war 文件期间?
我想避免使用 Derby 服务器,并且我还使用注释而不是 XML 配置。这是我原来的 PersistConfig 类:
package com.example.spring.config;
import java.beans.PropertyVetoException;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.derby.jdbc.EmbeddedDataSource;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.datasource.embedded.ConnectionProperties;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseConfigurer;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@ComponentScan({"com.example.spring.dao.jpa"})
@EnableTransactionManagement // <-- enable @Transactional annotations for spring @Component and stereotypes
public class PersistConfig{
@Bean
public HibernateExceptionTranslator exceptionTranslator() {
return new HibernateExceptionTranslator();
}
@Bean
public LocalSessionFactoryBean localSessionFactoryBean(DataSource dataSource, JpaVendorAdapter vendorAdapter) {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(dataSource);
localSessionFactoryBean.setPackagesToScan("com.example.one", "com.example.two");
Properties properties = new Properties();
properties.putAll(vendorAdapter.getJpaPropertyMap());
localSessionFactoryBean.setHibernateProperties(properties);
return localSessionFactoryBean;
}
@Bean
public HibernateTransactionManager hibernateTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager(sessionFactory);
return hibernateTransactionManager;
}
@Configuration
public static class DevelopmentConfig{
@Bean
public DataSource dataSource() throws SQLException, PropertyVetoException {
DataSource dataSource = new SimpleDriverDataSource(new org.apache.derby.jdbc.EmbeddedDriver(), "jdbc:derby:C:\\Users\\Kevin\\Desktop\\DerbyDB", "", "");
System.out.println("RETURNING DATASOURCE");
return dataSource;
}
@Bean
JpaVendorAdapter vendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabase(Database.DERBY);
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.DerbyDialect");
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
vendorAdapter.getJpaPropertyMap().put("hibernate.hbm2ddl.auto", "update");
vendorAdapter.getJpaPropertyMap().put("hbm2ddl.auto", "update");
return vendorAdapter;
}
}
}
我尝试使用 Runtime.addShutdownHook() 将关闭挂钩添加到整个 JVM,在其中我手动断开与 Derby 数据库的连接,但这似乎从未触发过。
然后我被告知查看 EmbeddedDatabaseConfigurer 接口以添加一个 Spring 关闭回调,我在其中手动关闭数据库连接,这就是我想出的:
package com.example.spring.config;
import java.beans.PropertyVetoException;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.derby.jdbc.EmbeddedDataSource;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.datasource.embedded.ConnectionProperties;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseConfigurer;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@ComponentScan({"com.example.spring.dao.jpa"})
@EnableTransactionManagement // <-- enable @Transactional annotations for spring @Component and stereotypes
public class PersistConfig implements EmbeddedDatabaseConfigurer {
@Bean
public HibernateExceptionTranslator exceptionTranslator() {
return new HibernateExceptionTranslator();
}
@Bean
public LocalSessionFactoryBean localSessionFactoryBean(DataSource dataSource, JpaVendorAdapter vendorAdapter) {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(dataSource);
localSessionFactoryBean.setPackagesToScan("com.example.one", "com.example.two");
Properties properties = new Properties();
properties.putAll(vendorAdapter.getJpaPropertyMap());
localSessionFactoryBean.setHibernateProperties(properties);
return localSessionFactoryBean;
}
@Bean
public HibernateTransactionManager hibernateTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager(sessionFactory);
return hibernateTransactionManager;
}
@Configuration
public static class DevelopmentConfig{
@Bean
public DataSource dataSource() throws SQLException, PropertyVetoException {
DataSource dataSource = new SimpleDriverDataSource(new org.apache.derby.jdbc.EmbeddedDriver(), "jdbc:derby:C:\\Users\\Kevin\\Desktop\\DerbyDB", "", "");
System.out.println("RETURNING DATASOURCE");
return dataSource;
}
@Bean
JpaVendorAdapter vendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabase(Database.DERBY);
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.DerbyDialect");
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
vendorAdapter.getJpaPropertyMap().put("hibernate.hbm2ddl.auto", "update");
vendorAdapter.getJpaPropertyMap().put("hbm2ddl.auto", "update");
return vendorAdapter;
}
}
@Override
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
System.out.println("CONFIGURE");
properties.setDriverClass(org.apache.derby.jdbc.EmbeddedDriver.class);
properties.setUrl("jdbc:derby:C:\\Users\\Kevin\\Desktop\\DerbyDB");
}
@Override
public void shutdown(DataSource ds, String databaseName) {
System.out.println("SHUTTING DOWN");
try {
DriverManager.getConnection("jdbc:derby:C:\\Users\\Kevin\\Desktop\\DerbyDB;shutdown=true");
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
但是,configureConnectionProperties() 函数和 shutdown() 函数似乎都没有被调用。我显然不知道我在做什么,所以任何指针都非常感谢。
【问题讨论】:
-
只有在重新部署应用程序时才会出现问题,还是在以下情况下也会出现问题:1/停止,取消部署,稍等(> 30秒),重新部署和2/停止tomcat,重新启动雄猫?
-
@SergeBallesta 无论我做什么都会发生:我尝试停止 tomcat,从 Tomcat 的 webapp 目录中删除 .war 和目录,然后将新的 .war 文件复制到 webapp 目录中,然后再次启动Tomcat。我还尝试通过复制新的 .war 文件来“热部署”。两者都生成 SQLException。
标签: java spring tomcat spring-mvc derby