How to start H2 TCP server on spring running boot application?

I can start the H2 TCP server (the database in the file) when starting the application as a Spring Boot app by adding the following line to the main SpringBootServletInitializer method:

@SpringBootApplication public class NatiaApplication extends SpringBootServletInitializer { public static void main(String[] args) { Server.createTcpServer().start(); SpringApplication.run(NatiaApplication.class, args); } } 

But if I run the WAR file on Tomcat, it does not work, because the main method is not called. Is there a better universal way to start the H2 TCP server when the application starts before the beans get initialized? I use Flyway (autoconfig) and it fails on “Connection refused: connect”, probably because the server is not running. Thanks.

+5
source share
5 answers

This solution works for me. It starts the H2 server if the application runs as a Spring Boot application, as well as if it runs on Tomcat. Creating the H2 server as a bean did not work because the Flyway bean was created earlier and the Connection failed.

 @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); } } } 
+5
source

For packing WAR you can do this:

 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
source

Yup, directly from the documentation , you can use the bean link:

 <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" /> 

There is also a servlet listener option that automatically starts / stops it.

This answers your question, but I think you should probably use native mode if it is deployed with your Spring Boot application. This is much faster and easier than resources. You simply provide the correct URL and start the database:

 jdbc:h2:/usr/share/myDbFolder 

( straight from the cover ).

+2
source

You can do the following:

 @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; } } 
0
source

There is a caution that has not been addressed in other answers. What you need to know is that starting the server is a transient dependency on your DataSource bean. This is because the DataSource only needs a network connection, not a bean.

The problem is that spring-boot will not be aware of the need to start the h2 database before creating the DataSource , so when you start the application you can get a connection exception.

When using spring -foundation, this is not a problem, since you start the database server launch in RootConfig with the database as a child. When using spring AFAIK boot, there is only one context.

To get around this, you can create an Optional<Server> dependency on the data source. Optional reason is that you cannot always start the server (configuration parameter), for which you may have a production database.

 @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; } 
0
source

All Articles