H2 in-memory database. Table not found
Asked Answered
G

28

254

I've got a H2 database with URL "jdbc:h2:test". I created a table with the following code

CREATE TABLE PERSON (
   ID INT PRIMARY KEY, 
   FIRSTNAME VARCHAR(64), 
   LASTNAME VARCHAR(64)
);

I then select everything from this (empty) table SELECT * FROM PERSON. So far, so good.

However, if I change the URL to "jdbc:h2:mem:test", the only difference being the database is now in memory only, this gives this error

org.h2.jdbc.JdbcSQLException: Table "PERSON" not found; SQL
statement: SELECT * FROM PERSON [42102-154]

I'm probably missing something simple here, but any help would be appreciated.

Ginni answered 23/4, 2011 at 10:51 Comment(6)
After switching to in-memory mode you got to create the table Person again. H2 doesn't know anything about the database you created on disk before.Dollar
The rest of the program didn't change - I did create the table again.Ginni
See: Keep H2 in-memory database between connectionsArriola
How do you connect? I suspect you are connecting to different database, as you don't specify anything(hint: it cannot be created in server mode just by changing URL). In-memory database needs to be created in server mode to allow more than 1 connection; without server mode, it's private to the same JVM and cannot be connected from other processes. That's why I think you are recreating the db and you don't see the data of application db. So, or you create a file and use server mode, or you create in-memory db but also in server mode. And you need to connect with TCP. See my answer.Saphena
@Saphena Thanks for the input but this question has already been answered correctly over 10 years ago.Ginni
Actually just found that if I use the accepted answer, next launch of app will see "Address already in use" because the previous session occupies the same port, so there's some side effect and the correct answer may not be the real solution here.Saphena
H
433

DB_CLOSE_DELAY=-1

hbm2ddl closes the connection after creating the table, so h2 discards it.

If you have your connection-url configured like this

jdbc:h2:mem:test

the content of the database is lost at the moment the last connection is closed.

If you want to keep your content you have to configure the url like this

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

If doing so, h2 will keep its content as long as the vm lives.

Notice the semicolon (;) rather than colon (:).

See the In-Memory Databases section of the Features page. To quote:

By default, closing the last connection to a database closes the database. For an in-memory database, this means the content is lost. To keep the database open, add ;DB_CLOSE_DELAY=-1 to the database URL. To keep the content of an in-memory database as long as the virtual machine is alive, use jdbc:h2:mem:test;DB_CLOSE_DELAY=-1.

Heiskell answered 9/5, 2011 at 12:39 Comment(7)
I found the problem myself in the mean time, but yeah, this is completely correct. Thanks!Ginni
And it has to be a named in-memory database, i.e. jdbc:h2:mem:;DB_CLOSE_DELAY=-1 does not work.Ferriter
how can we store data in the file instead of memory ?Selfhelp
if you use lower case for naming your tables in a code you should know that H2 uppercase everything by default use DATABASE_TO_UPPER=false to avoid it e.g. jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;Calvert
@OleksandrPetrenko - that trailing ';' seems to cause problems. I think you need to leave that out.Papule
This behaviour of H2 is documented here: h2database.com/html/features.html#in_memory_databasesArtemis
@Oleksandr Petrenko exactly solved my problem, thanks very much :)Ascertain
G
162

I know this was not your case but I had the same problem because H2 was creating the tables with UPPERCASE names then behaving case-sensitive, even though in all scripts (including in the creation ones) i used lowercase.

Solved by adding ;DATABASE_TO_UPPER=false to the connection URL.

Genuflection answered 29/7, 2013 at 13:42 Comment(4)
Wow - I'm very glad you shared this one! never would have thought of that.Dalenedalenna
Not the solution to the question that was asked, but the solution to the problem I was having when searching with the same question!Comeuppance
Is it possible to set this DATABASE_TO_UPPER=false thing as an SQL statement in an init script? (Similarly as a statement like SET MODE PostgreSQL;) If so, what is the exact syntax?Plasterboard
How can I upvote this multiple times? Thanks a lot! This should be part of the first answer.Kenna
L
104

For Spring Boot 2.4+ use spring.jpa.defer-datasource-initialization=true in application.properties

Lanfranc answered 22/6, 2021 at 15:42 Comment(7)
Spot on :) Solved my issue. Thanks!Miaow
This one is indeed beautiful solution. Can you please explain what does this statement do?Ocrea
Thanks brother..Yugoslav
This is the best solution by far, works like a charmParmenides
This is what fixed it for me. Can you explain what that command does?Clog
@AlGrant it defers data source initialization until after any EntityManagerFactory beans have been created and initialized. (docs.spring.io/spring-boot/docs/current/reference/html/…)Praetorian
I was still getting h2 data.sql Table "TABLE_NAME" not found (this database is empty) but after adding "spring.jpa.defer-datasource-initialization=true" my issue got resolved. Pls note that I had already added ";DB_CLOSE_DELAY=-1" and still was getting Table not found.Assamese
A
12

Hard to tell. I created a program to test this:

package com.gigaspaces.compass;

import org.testng.annotations.Test;

import java.sql.*;

public class H2Test {
@Test
public void testDatabaseNoMem() throws SQLException {
    testDatabase("jdbc:h2:test");
}
@Test
public void testDatabaseMem() throws SQLException {
    testDatabase("jdbc:h2:mem:test");
}

private void testDatabase(String url) throws SQLException {
    Connection connection= DriverManager.getConnection(url);
    Statement s=connection.createStatement();
    try {
    s.execute("DROP TABLE PERSON");
    } catch(SQLException sqle) {
        System.out.println("Table not found, not dropping");
    }
    s.execute("CREATE TABLE PERSON (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(64), LASTNAME VARCHAR(64))");
    PreparedStatement ps=connection.prepareStatement("select * from PERSON");
    ResultSet r=ps.executeQuery();
    if(r.next()) {
        System.out.println("data?");
    }
    r.close();
    ps.close();
    s.close();
    connection.close();
}
}

The test ran to completion, with no failures and no unexpected output. Which version of h2 are you running?

Ayeaye answered 23/4, 2011 at 11:47 Comment(2)
I'll try this tomorrow, thanks. The H2 version is the one I got off the site today: 1.3.154Ginni
I think I found the problem. When I close the connection the table was created with, then open a new one, the db is gone. When I open a new connection before I close the previous one, the data remains. When I use a file, the data (obviously) always remains.Ginni
M
12

When opening the h2-console, the JDBC URL must match the one specified in the properties:

spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb

spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true

spring.h2.console.enabled=true

enter image description here

Which seems obvious, but I spent hours figuring this out..

Music answered 30/8, 2019 at 5:31 Comment(1)
thanks on an interview assignment due in next few hours and lost a couple of valuable hours till I saw this comment , which was the issue !Reenter
C
11

One reason can be that jpa tries to insert data before creating table structure, in order to solve this problem , insert this line in application.properties :

spring.jpa.defer-datasource-initialization=true
Checkered answered 29/12, 2021 at 23:2 Comment(0)
W
8

The H2 in-memory database stores data in memory inside the JVM. When the JVM exits, this data is lost.

I suspect that what you are doing is similar to the two Java classes below. One of these classes creates a table and the other tries to insert into it:

import java.sql.*;

public class CreateTable {
    public static void main(String[] args) throws Exception {
        DriverManager.registerDriver(new org.h2.Driver());
        Connection c = DriverManager.getConnection("jdbc:h2:mem:test");
        PreparedStatement stmt = c.prepareStatement("CREATE TABLE PERSON (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(64), LASTNAME VARCHAR(64))");
        stmt.execute();
        stmt.close();
        c.close();
    }
}

and

import java.sql.*;

public class InsertIntoTable {
    public static void main(String[] args) throws Exception {
        DriverManager.registerDriver(new org.h2.Driver());
        Connection c = DriverManager.getConnection("jdbc:h2:mem:test");
        PreparedStatement stmt = c.prepareStatement("INSERT INTO PERSON (ID, FIRSTNAME, LASTNAME) VALUES (1, 'John', 'Doe')");
        stmt.execute();
        stmt.close();
        c.close();
    }
}

When I ran these classes one after the other, I got the following output:

C:\Users\Luke\stuff>java CreateTable

C:\Users\Luke\stuff>java InsertIntoTable
Exception in thread "main" org.h2.jdbc.JdbcSQLException: Table "PERSON" not found; SQL statement:
INSERT INTO PERSON (ID, FIRSTNAME, LASTNAME) VALUES (1, 'John', 'Doe') [42102-154]
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
        at org.h2.message.DbException.get(DbException.java:167)
        at org.h2.message.DbException.get(DbException.java:144)
        ...

As soon as the first java process exits, the table created by CreateTable no longer exists. So, when the InsertIntoTable class comes along, there's no table for it to insert into.

When I changed the connection strings to jdbc:h2:test, I found that there was no such error. I also found that a file test.h2.db had appeared. This was where H2 had put the table, and since it had been stored on disk, the table was still there for the InsertIntoTable class to find.

Wingding answered 23/4, 2011 at 12:7 Comment(3)
Please note that the registerDriver() call is unnecessary: First of: a simple Class.forName() does the same for most JDBC drivers and (more importantly) it's completely unnecessary for Java 6 und up, which auto-detects (compatible) JDBC drivers on the classpath.Mutton
An in memory db exists only as long as the program that owns the memory is running? Wow, I had no idea >_< But really, I know what I'm trying to do. Reading your answer, I'm not sure you do.Ginni
@Jorn: I might not know what you're trying to do, I'm guessing based on what information you provided. It may have been more helpful to provide an SSCCE (sscce.org) demonstrating your problem - I wouldn't call your question 'complete' in that respect. I provided the above answer because there are people on SO (newcomers to programming, mainly) that might think that an 'in-memory' database stores the data in the computer's memory somewhere where it could survive between program invocations. Your question wasn't complete enough to convince me you weren't one of these people.Wingding
V
7

I have tried to add

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

However, that didn't helped. On the H2 site, I have found following, which indeed could help in some cases.

By default, closing the last connection to a database closes the database. For an in-memory database, this means the content is lost. To keep the database open, add ;DB_CLOSE_DELAY=-1 to the database URL. To keep the content of an in-memory database as long as the virtual machine is alive, use jdbc:h2:mem:test;DB_CLOSE_DELAY=-1.

However, my issue was that just the schema supposed to be different than default one. So insted of using

JDBC URL: jdbc:h2:mem:test

I had to use:

JDBC URL: jdbc:h2:mem:testdb

Then the tables were visible

Verticillate answered 25/12, 2016 at 11:47 Comment(1)
thanks, "testdb" was a fix for me too (in addition to "DB_CLOSE_DELAY=-1") !Additional
E
7

Solved by creating a new src/test/resources folder + insert application.properties file, explicitly specifying to create a test dbase :

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create
Electrotherapy answered 3/1, 2019 at 9:48 Comment(0)
T
6

I had the same problem and changed my configuration in application-test.properties to this:

#Test Properties
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop

And my dependencies:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.198</version>
        <scope>test</scope>
    </dependency>

And the annotations used on test class:

@RunWith(SpringRunner.class)
@DataJpaTest
@ActiveProfiles("test")
public class CommentServicesIntegrationTests {
...
}
Tack answered 4/4, 2019 at 10:35 Comment(0)
A
6

I was trying to fetch table meta data, but had the following error:

Using:

String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";

DatabaseMetaData metaData = connection.getMetaData();
...
metaData.getColumns(...);

returned an empty ResultSet.

But using the following URL instead it worked properly:

String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false";

There was a need to specify: DATABASE_TO_UPPER=false

Arbe answered 26/4, 2019 at 18:45 Comment(1)
This doesn't add anything not covered by this answer. From Review.Garneau
G
4

I have tried adding ;DATABASE_TO_UPPER=false parameter, which it did work in a single test, but what did the trick for me was ;CASE_INSENSITIVE_IDENTIFIERS=TRUE.

At the end I had: jdbc:h2:mem:testdb;CASE_INSENSITIVE_IDENTIFIERS=TRUE

Moreover, the problem for me was when I upgraded to Spring Boot 2.4.1.

Gosney answered 17/12, 2020 at 11:31 Comment(1)
I upgraded Spring Boot from 1.3.3.RELEASE to 2.4.4 and adding ;CASE_INSENSITIVE_IDENTIFIERS=TRUE also did the trick for me.Ladanum
R
4

I might be a little late to the party, but I faced exactly the same error and I tried pretty much every solution mentioned here and on other websites such as *DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1; DB_CLOSE_ON_EXIT=FALSE; IGNORECASE=TRUE*. But nothing worked for me.

What worked for me was renaming data.sql to import.sql

I found it here - https://mcmap.net/q/99361/-spring-boot-loading-initial-data

Or

For Spring Boot 2.4+ use spring.jpa.defer-datasource-initialization=true in application.properties (mentioned here - https://mcmap.net/q/109571/-h2-in-memory-database-table-not-found)

I realize other solutions are more logical but none of them worked for me and this did.

Rottenstone answered 29/7, 2021 at 6:31 Comment(1)
The rename to import.sql is what worked for me. I feel like the "defer=true" is a workaround...while the rename is the "actually fix it for Spring 2.5+". Thank you.Valverde
I
3

Had similar problem Solution was to add the following to application.properties

spring.jpa.defer-datasource-initialization=true

Into answered 29/8, 2022 at 2:14 Comment(1)
This works and makes perfect sense if you are creating the table with JDBC.Bonaparte
C
2

I came to this post because I had the same error.

In my case the database evolutions weren't been executed, so the table wasn't there at all.

My problem was that the folder structure for the evolution scripts was wrong.

from: https://www.playframework.com/documentation/2.0/Evolutions

Play tracks your database evolutions using several evolutions script. These scripts are written in plain old SQL and should be located in the conf/evolutions/{database name} directory of your application. If the evolutions apply to your default database, this path is conf/evolutions/default.

I had a folder called conf/evolutions.default created by eclipse. The issue disappeared after I corrected the folder structure to conf/evolutions/default

Christiansand answered 23/12, 2014 at 21:32 Comment(0)
A
2

Had the exact same issue, tried all the above, but without success. The rather funny cause of the error was that the JVM started too fast, before the DB table was created (using a data.sql file in src.main.resources). So I've put a Thread.sleep(1000) timer to wait for just a second before calling "select * from person". Working flawlessly now.

application.properties:

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

data.sql:

create table person
(
id integer not null,
name varchar(255) not null,
location varchar(255),
birth_date timestamp,
primary key(id)
);

insert into person values (
10001, 'Tofu', 'home', sysdate()
);

PersonJdbcDAO.java:

    public List<Person> findAllPersons(){
    return jdbcTemplate.query("select * from person", 
        new BeanPropertyRowMapper<Person>(Person.class));
}

main class:

Thread.sleep(1000);
logger.info("All users -> {}", dao.findAllPersons());
Albertalberta answered 31/3, 2020 at 10:22 Comment(0)
E
2

I found it working after adding the dependency of Spring Data JPA -

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

Add H2 DB configuration in application.yml -

spring:
  datasource:
    driverClassName: org.h2.Driver
    initialization-mode: always
    username: sa
    password: ''
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
  h2:
    console:
      enabled: true
      path: /h2
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: none
Ephod answered 3/5, 2020 at 7:11 Comment(1)
Question has nothing to do with spring, and solving simple problems bu throwing in frameworks is crudeLigule
B
2

I have tried the above solution,but in my case as suggested in the console added the property DB_CLOSE_ON_EXIT=FALSE, it fixed the issue.

 spring.datasource.url=jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false;DB_CLOSE_ON_EXIT=FALSE
Bonsai answered 22/7, 2020 at 9:33 Comment(0)
T
1
<bean id="benchmarkDataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1" />
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>
Tympanites answered 31/12, 2016 at 18:35 Comment(0)
D
1

The issue can also happen if there was error while generating the table.

If the entities use any features which are not supported by H2 (for example, specifying a non-standard columnDefinition), the schema generation will fail and test will continue without the database generated.

In this case, somewhere in the logs you will find this:

WARN ExceptionHandlerLoggedImpl: GenerationTarget encountered exception accepting command :
 Error executing DDL "create table ..." via JDBC Statement
Derayne answered 27/5, 2022 at 11:27 Comment(0)
E
1

If you are using @DataJpaTest you need to bear in mind that by default it ignores the datasource defined in your properties and creates a new one of its own.

Due to this, most of the solutions will not work, specially if you are trying to use an in-memory database in combination with Flyway/Liquibase. For instance, DB_CLOSE_DELAY=-1 connection property is ignored and setting spring.jpa.defer-datasource-initialization=true causes a circular dependency with Flyway.

Allowing Hibernate to create the schema with ddl-auto=create is not ideal either if you want to ensure your migration scripts actually work, so the best solution is to use the AutoConfigureTestDatabase annotation to tell @DataJpaTest not to create its own database and to use the one defined in your properties files.

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class YourDatabaseIntegrationTest {
    ...
}
Expletive answered 22/6, 2023 at 22:46 Comment(0)
U
0

In my case missing table error was happening during jpa test, table was created by schem.sql file, problem was fixed after puting @org.springframework.transaction.annotation.Transactional on test

Unexampled answered 13/5, 2021 at 18:11 Comment(0)
S
0

In my case, I had used the special keywords for my column-names in the table, H2 Database. If you're using different databases avoid those special keywords across different databases. Spring & Hibernate isn't smart enough to tell you exactly which column names are prohibited or where the exact error is in the table-creation. Keywords such as;

desc, interval, metric

To resolve the issues I was experiencing, I renamed those fields to:

descr, time_interval, time_metric

http://www.h2database.com/html/advanced.html

Sporocyst answered 22/9, 2021 at 7:4 Comment(0)
A
0
   Use the same in applications.properties file
   
   spring.jpa.show-sql=true
   spring.datasource.url=jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false
   DB_CLOSE_ON_EXIT=FALSE
   spring.data.jpa.repositories.bootstrap-mode=default
   spring.h2.console.enabled=true spring.jpa.generate-ddl=true
   spring.jpa.hibernate.ddl-auto=create
   spring.datasource.driverClassName=org.h2.Driver
   spring.jpa.defer-datasource-initialization=true
Atalya answered 10/10, 2021 at 21:33 Comment(0)
M
0
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "user" not found; SQL statement:

in my case, my table name was user but from H2 2.1.212 user is reserved so couldn't make the table

changed table name users by @Table(name="users") and

datasource:
  url: jdbc:h2:mem:testdb;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;

and it works now

Ms answered 4/10, 2022 at 14:51 Comment(0)
A
0

This might be a beginners mistake but the error in my case was that, when I wanted to switch my DB to H2, I omitted a property that needed changing.

Namely: spring.jpa.properties.hibernate.dialect: org.hibernate.dialect.H2Dialect

Other usual suspects could be:

  • spring.datasource.driver-class-name: org.h2.Driver
  • spring.datasource.url: jdbc:h2:file:./your/path
  • spring.jpa.hibernate.ddl-auto: where you might have set a wrong value

I'm not sure whether those would result in different error messages. However, they are still worth a quick check.

Adriel answered 23/5, 2023 at 9:43 Comment(0)
A
0

The accepted Answer by reini2901 is correct. In addition, here is an example of configuring by way of a DataSource object.

javax.sql.DataSource

Using a DataSource enables you to externalize the connection credentials (user name, password, server address, etc.). Rather than hard-coding these facts in your code, they can be configured outside the app. You can use a directory/name service such as an LDAP server or a Jakarta EE server to store the credentials info. Then your app uses Java Naming and Directory Interface (JNDI) to retrieve the info as a DataSource object at runtime.

As part of a transition to externalizing, here we hard-code the credentials info in a DataSource object in our code.

  • The mem in the URL means an in-memory database.
  • The DB_CLOSE_DELAY=-1 keeps the database open for further connections. 👉🏽 Closing an in-memory database instantly destroys it.

Regarding syntax… Notice the SEMICOLON ; as a delimiter separating the DB_CLOSE_DELAY=-1.

Using Java 21 with H2 Database Engine 2.2.224.

private javax.sql.DataSource dataSource ( )
{
    org.h2.jdbcx.JdbcDataSource ds = new JdbcDataSource ( );  // Implementation of `DataSource` bundled with H2.
    ds.setURL ( "jdbc:h2:mem://Users/basil_dot_work/DataSourceDemoDB;DB_CLOSE_DELAY=-1" );
    ds.setUser ( "scott" );
    ds.setPassword ( "tiger" );
    ds.setDescription ( "An example database demonstrating javax.sql.DataSource." );
    return ds;
}

Full example follows.

package work.basil.example.db;

import org.h2.jdbcx.JdbcDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.OffsetDateTime;

public class ThisMonth
{
    public static void main ( String[] args )
    {
        ThisMonth app = new ThisMonth ( );
        app.demo ( );
    }

    private void demo ( )
    {
        DataSource dataSource = this.dataSource ( );
        String sql = """
                SELECT CURRENT_TIMESTAMP ;
                """;
        try (
                Connection connection = dataSource.getConnection ( ) ;
                Statement statement = connection.createStatement ( ) ;
                ResultSet resultSet = statement.executeQuery ( sql ) ;
        )
        {
            while ( resultSet.next ( ) )
            {
                OffsetDateTime now = resultSet.getObject ( 1 , OffsetDateTime.class );
                System.out.println ( "now = " + now );
            }
        } catch ( SQLException e )
        {
            throw new RuntimeException ( e );
        }
    }

    private javax.sql.DataSource dataSource ( )
    {
        org.h2.jdbcx.JdbcDataSource ds = new JdbcDataSource ( );  // Implementation of `DataSource` bundled with H2.
        ds.setURL ( "jdbc:h2:mem://Users/basil_dot_work/DataSourceDemoDB;DB_CLOSE_DELAY=-1" );
        ds.setUser ( "scott" );
        ds.setPassword ( "tiger" );
        ds.setDescription ( "An example database demonstrating javax.sql.DataSource." );
        return ds;
    }
}

When run:

now = 2024-01-17T20:08:26.570651-08:00

Arriola answered 18/1 at 4:15 Comment(0)
S
-1

I suspect the database you opened is a brand new db, not your application db. This is because:

  • H2 in-memory database by default is private to the JVM and the classloader. It cannot be connected from another process/with TCP from same machine/from another machine; that's why all the guides suggest using H2 console, because that's within the same JVM of your application so it can access the database(however, my H2 console shipped with Spring 2.6 is not working, I need to find another way)
  • H2 database can be launched in server mode, but ";AUTO_SERVER=true" does not work with in-memory db; it only can be added to the URL when you use a file based db; and to visit it you need to use absolute path to the db file, which is not portable and is ugly; additionally, auto-generation of tables are not done when you use a file so you need to create an init.sql to create tables. AND, when you connect H2 still tells you that you need server mode, because there is already one connection to the db(your app) and to allow 1+ connection, you need server mode

So in both cases you need server mode. How?

In Spring you need to create the DB as a bean(thanks to How to enable H2 Database Server Mode in Spring Boot); put this into a @Configuration and you are done:

@Bean(initMethod = "start", destroyMethod = "stop")
public Server h2Server() throws SQLException {
    return Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "1234"); // or any other port
}

Your db url:

spring:
  datasource:
    url: jdbc:h2:mem:test
    driver-class-name: org.h2.Driver
    port: 1234
    username: sa
    password: sa

That's all. You can connect with H2 console, or DB Navigator, or other tools along with your app right now. The connection string is:

jdbc:h2:tcp://localhost:1234/mem:test
Saphena answered 19/2, 2023 at 16:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.