javaspringormh2h2db

How to show content of local h2 database(web console)?


Recently I joined a new team and here guys use h2 for stub service.

I was wondering whether I can show the content of this database using web interface. At work it is available by going to localhost:5080

I have a project where I use h2 database, but I cannot see the h2 web console when I hit localhost:5080

I tried also localhost:8082 - it also doesn't work.

My project configuration (works successfully):

     <bean id="wrappedDataSource" class="net.bull.javamelody.SpringDataSourceFactoryBean">
        <property name="targetName" value="dataSource" />
     </bean>

     <bean id="wrappedDataSource" class="net.bull.javamelody.SpringDataSourceFactoryBean">
            <property name="targetName" value="dataSource" />
        </bean>

        <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
            <property name="driverClassName" value="org.h2.Driver" />
            <property name="url" value="jdbc:h2:~/test;MODE=PostgreSQL" />
            <property name="username" value="sa" />
            <property name="password" value="" />
        </bean>

        <bean id="sessionFactory"
              class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
            <property name="dataSource" ref="wrappedDataSource"/>
            <property name="configLocation">
                <value>classpath:hibernate-test.cfg.xml</value>
            </property>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.show_sql">false</prop>
                    <prop key="hibernate.connection.charSet">UTF-8</prop>
                    <prop key="hibernate.format_sql">true</prop>
                    <prop key="hbm2ddl.auto">create-drop</prop>
                </props>
            </property>
        </bean>

        <context:property-placeholder location="classpath:jdbc.properties"/>

I have not ideas how to access to h2 web console. please help.

P.S.

I see mentions of h2 only in .m2 folder

P.S.2

I noticed that web console available by http://localhost:8082/ if replace url in configuration with:

<property name="url" value="jdbc:h2:tcp://localhost/~/test;MODE=PostgreSQL" />

But it works if I already start h2(in .m2 folder find h2 jar file and hit double click)

If h2 is not started when I start application - i see following error:

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:94)
    ...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dbInitializer': Invocation of init method failed; nested exception is org.hibernate.exception.GenericJDBCException: Could not open connection
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136)
    ...
Caused by: org.hibernate.exception.GenericJDBCException: Could not open connection
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)
    ...
Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Соединение разорвано: "java.net.ConnectException: Connection refused: connect: localhost"
Connection is broken: "java.net.ConnectException: Connection refused: connect: localhost" [90067-182])
    at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1549)
    ...
Caused by: org.h2.jdbc.JdbcSQLException: Соединение разорвано: "java.net.ConnectException: Connection refused: connect: localhost"
Connection is broken: "java.net.ConnectException: Connection refused: connect: localhost" [90067-182]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
    ...
Caused by: java.net.ConnectException: Connection refused: connect
    at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
    ...

I want to achieve that h2 starts if it not started when I start my application.

P.S.3

I have tried to wrote following code:

Server server = null;
try {
    server = Server.createTcpServer("-tcpAllowOthers").start();
    Class.forName("org.h2.Driver");
    Connection conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/~/test;MODE=PostgreSQL", "sa", "");
 } catch (Exception e) {
    LOG.error("Error while initialize", e);
 }

I execute it and after I am trying to type localhost:9092 in my browser.

At this moment downloads file. inside file the following content:

Version mismatch, driver version is “0” but server version is “15”

my h2 version 1.4.182

P.S.4

This code works:

public class H2Starter extends ContextLoaderListener {
    private static final Logger LOG = LoggerFactory.getLogger(H2Starter.class);

    @Override
    public void contextInitialized(ServletContextEvent event) {

        startH2();
        super.contextInitialized(event);
    }

    private static void startH2() {

        try {
            Server.createTcpServer("-tcpAllowOthers").start();
            Class.forName("org.h2.Driver");
            DriverManager.getConnection("jdbc:h2:tcp://localhost/~/test;MODE=PostgreSQL;AUTO_SERVER=TRUE", "sa", "");

            Server.createWebServer().start();
        } catch (Exception e) {
            LOG.error("cannot start H2 [{}]", e);
        }
    }

    public static void main(String[] args) {
        startH2();
    }
}

but I need to invoke it only when concrete spring profile active(now it works always)


Solution

  • Let's split the question into two parts.

    Depending on how you specify the connection to H2, you'll get different operational modes.

    Modes are: Embedded, In-Memory, Server.

    jdbc:h2:~/test gives you a H2 instance in embedded mode. The embedded mode has a limitation of being accessible only through the same class loader and same JVM (proof)

    jdbc:h2:mem:test gets you an in-memory H2 instance. That is also not accessible from outer world.

    jdbc:h2:tcp://localhost/test will start H2 server and it will be accessible from outside of JVM server mode but with one limitation - the server needs to be started before the connection is made.

    The last limitation is causing your Connection refused: connect: localhost" exception.

    To sum everything up:

    Update

    Just noticed that you want to start the server in the process of launching application.

    You can do that in several ways, depending how do you start the application:

    Update 2

    If connection to the local database is needed only for developing / debugging purposes I would setup everything using maven profile. Answers from this question will solve that.

    If you need access to the H2 database in production (I can hardly imagine any use-case for that) it's better to do that in spring. Mainly because the application container / environment setup is likely to be different in production (compared to development environment).

    To address the question regarding if to start the server outside of Spring context or not - it all depends on the requirements. One thing you should note is that the server should be started before the datasource is started (otherwise the spring context will not load)

    Update 3

    Unfortunately I'm not able to give you a working solution, but according to the JavaDocs there is a difference between TCP server and Web server. Take a closer look to the JavaDoc of H2 Server class.

    I guess you should use Server.createWebServer() method to create the server (the difference between TCP server and Web server is that

    Another great class you could use org.h2.tools.Console (JavaDoc here) Just run the main method of Console and I guess that should solve everything.