通过在SpringBootServletInitializer主方法中添加以下行,将应用程序作为Spring Boot应用程序运行时,我能够启动H2 TCP服务器(文件中的数据库):
@SpringBootApplication
public class NatiaApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
Server.createTcpServer().start();
SpringApplication.run(NatiaApplication.class, args);
}
}
但是如果我在Tomcat上运行WAR文件,它就不起作用,因为没有调用main方法。在bean初始化之前,如何在应用程序启动时启动H2 TCP服务器有更好的通用方法吗?我使用Flyway(autoconfig)并且它失败了#34;连接被拒绝:连接"可能是因为服务器没有运行。谢谢。
答案 0 :(得分:6)
此解决方案适合我。如果应用程序作为Spring Boot应用程序运行,并且如果它在Tomcat上运行,它将启动H2服务器。创建H2服务器作为bean不起作用,因为Flyway bean是先前创建的并且在#34; Connection refused"上失败了。
@SpringBootApplication
@Log
public class NatiaApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
startH2Server();
SpringApplication.run(NatiaApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
startH2Server();
return application.sources(NatiaApplication.class);
}
private static void startH2Server() {
try {
Server h2Server = Server.createTcpServer().start();
if (h2Server.isRunning(true)) {
log.info("H2 server was started and is running.");
} else {
throw new RuntimeException("Could not start H2 server.");
}
} catch (SQLException e) {
throw new RuntimeException("Failed to start H2 server: ", e);
}
}
}
答案 1 :(得分:2)
对于WAR包装,您可以这样做:
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
Server.createTcpServer().start();
return new Class[] { NatiaApplication.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
答案 2 :(得分:2)
是的,straight from the documentation,您可以使用bean引用:
<bean id = "org.h2.tools.Server"
class="org.h2.tools.Server"
factory-method="createTcpServer"
init-method="start"
destroy-method="stop">
<constructor-arg value="-tcp,-tcpAllowOthers,-tcpPort,8043" />
还有servlet listener option that auto-starts/stops it.
这回答了你的问题,但我认为如果它与你的Spring Boot应用程序一起部署,你应该使用嵌入式模式。这在资源上更快,更轻。您只需指定正确的URL,数据库就会启动:
jdbc:h2:/usr/share/myDbFolder
答案 3 :(得分:1)
你可以这样做:
@Configuration
public class H2ServerConfiguration {
@Value("${db.port}")
private String h2TcpPort;
/**
* TCP connection to connect with SQL clients to the embedded h2 database.
*
* @see Server
* @throws SQLException if something went wrong during startup the server.
* @return h2 db Server
*/
@Bean
public Server server() throws SQLException {
return Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", h2TcpPort).start();
}
/**
* @return FlywayMigrationStrategy the strategy for migration.
*/
@Bean
@DependsOn("server")
public FlywayMigrationStrategy flywayMigrationStrategy() {
return Flyway::migrate;
}
}
答案 4 :(得分:0)
在其他答案中没有考虑过一个警告。您需要注意的是,启动服务器是对DataSource
bean的短暂依赖。这是因为DataSource
只需要网络连接,而不是bean关系。
这导致的问题是spring-boot在创建DataSource
之前不会知道需要启动的h2数据库,因此在应用程序启动时可能会出现连接异常。
使用spring-framework,这不是一个问题,因为您将数据库服务器启动放在root配置中,并将数据库作为子项。使用弹簧靴AFAIK,只有一个上下文。
要解决此问题,您可以在数据源上创建Optional<Server>
依赖项。 Optional
的原因是您可能无法始终启动您可能拥有生产数据库的服务器(配置参数)。
@Bean(destroyMethod = "close")
public DataSource dataSource(Optional<Server> h2Server) throws PropertyVetoException {
HikariDataSource ds = new HikariDataSource();
ds.setDriverClassName(env.getProperty("db.driver"));
ds.setJdbcUrl(env.getProperty("db.url"));
ds.setUsername(env.getProperty("db.user"));
ds.setPassword(env.getProperty("db.pass"));
return ds;
}