web-dev-qa-db-fra.com

Base de données H2 en mémoire. Table non trouvée

J'ai une base de données H2 avec l'URL "jdbc:h2:test". Je crée une table en utilisant CREATE TABLE PERSON (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(64), LASTNAME VARCHAR(64));. Je sélectionne ensuite tout le contenu de cette table (vide) à l'aide de SELECT * FROM PERSON. Jusqu'ici tout va bien.

Cependant, si je change l'URL en "jdbc:h2:mem:test", la seule différence étant que la base de données est maintenant uniquement en mémoire, cela me donne un org.h2.jdbc.JdbcSQLException: Table "PERSON" not found; SQL statement: SELECT * FROM PERSON [42102-154]. Il me manque probablement quelque chose de simple ici, mais toute aide serait la bienvenue.

151
Jorn

hbm2ddl ferme la connexion après la création de la table, donc h2 la supprime.

Si vous avez configuré votre URL de connexion comme ceci

jdbc:h2:mem:test

le contenu de la base de données est perdu au moment de la fermeture de la dernière connexion.

Si vous voulez garder votre contenu, vous devez configurer l'URL comme ceci

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

Si cela est le cas, h2 conservera son contenu aussi longtemps que le vm  

272
reini2901

Je sais que ce n'était pas votre cas, mais j'avais le même problème car H2 créait les tables avec des noms UPPERCASE, puis se comportait de manière sensible à la casse, même si dans tous les scripts (y compris ceux de la création), j'utilisais des minuscules. 

Résolu en ajoutant ;DATABASE_TO_UPPER=false à l'URL de connexion. 

77
Cristian Vrabie

Dur à dire. J'ai créé un programme pour tester ceci: 

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();
}
}

Le test a abouti, sans échec ni sortie inattendue. Quelle version de h2 utilisez-vous?

10
Joseph Ottinger

La base de données H2 en mémoire stocke les données en mémoire dans la machine virtuelle. Lorsque la machine virtuelle Java est fermée, ces données sont perdues. 

Je suppose que ce que vous faites est similaire aux deux classes Java ci-dessous. L'une de ces classes crée une table et l'autre tente d'y insérer:

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();
    }
}

et

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();
    }
}

Quand j'ai couru ces classes les unes après les autres, j'ai obtenu le résultat suivant:

 C:\Utilisateurs\Luke\stuff> Java CreateTable 

 C:\Utilisateurs\Luke\stuff> Java InsertIntoTable 
 Exception dans le thread "principal" org.h2.jdbc.JdbcSQLException: Table " PERSON "non trouvé; Instruction SQL: 
 INSERER DANS LA PERSONNE (ID, PRENOM, NOM) VALEURS (1, 'John', 'Doe') [42102-154] 
 à org.h2.message.DbException.getJdbcSQLException (DbException.Java:327) 
 à org.h2.message.DbException.get (DbException.Java:167) 
 à org.h2.message.DbException.get (DbException.Java:144) 
 ...

Dès que le premier processus Java se termine, la table créée par CreateTable n'existe plus. Ainsi, lorsque la classe InsertIntoTable arrive, il n’ya pas de table dans laquelle insérer.

Lorsque j'ai changé les chaînes de connexion en jdbc:h2:test, j'ai constaté qu'il n'y avait pas d'erreur de ce type. J'ai aussi constaté qu'un fichier test.h2.db était apparu. C’est là que H2 avait placé la table et, comme elle avait été stockée sur disque, la table était toujours disponible pour la classe InsertIntoTable.

6
Luke Woodward

J'ai essayé d'ajouter

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

Cependant, cela n'a pas aidé. Sur le site H2 , j'ai trouvé ce qui suit, ce qui pourrait en effet aider dans certains cas.

Par défaut, la fermeture de la dernière connexion à une base de données ferme la base de données. Pour une base de données en mémoire, cela signifie que le contenu est perdu. Pour que la base de données reste ouverte, ajoutez; DB_CLOSE_DELAY = -1 à l'URL de la base de données. Pour conserver le contenu d'une base de données en mémoire tant que la machine virtuelle est en vie, utilisez jdbc: h2: mem: test; DB_CLOSE_DELAY = -1.

Cependant, mon problème était que juste le schéma supposé être différent de celui par défaut. Donc insted d'utiliser 

JDBC URL: jdbc:h2:mem:test

Je devais utiliser:

JDBC URL: jdbc:h2:mem:testdb

Puis les tables étaient visibles

3
DevDio

Je suis venu à ce poste parce que j'ai eu la même erreur.

Dans mon cas, les évolutions de la base de données n’ont pas été exécutées, la table n’y était donc pas du tout.

Mon problème était que la structure de dossier pour les scripts d'évolution était fausse.

à partir de: https://www.playframework.com/documentation/2.0/Evolutions

Play suit vos évolutions de base de données en utilisant plusieurs scripts d'évolutions. Ces scripts sont écrits en SQL ancien et doivent être situés dans le répertoire conf/evolutions/{nom de la base de données} de votre application. Si les évolutions s'appliquent à votre base de données par défaut, ce chemin est conf/evolutions/default.

J'avais un dossier appelé conf/evolutions.default créé par Eclipse. Le problème a disparu après avoir corrigé la structure de dossiers en conf/evolutions/default

1
Oscar Fraxedas

J'essayais d'extraire des métadonnées de table, mais j'avais l'erreur suivante:

En utilisant:

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

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

a retourné un ResultSet vide.

Mais en utilisant l’URL suivante, cela a fonctionné correctement:

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

Il était nécessaire de spécifier: DATABASE_TO_UPPER = false

J'ai eu le même problème et j'ai changé ma configuration dans application-test.properties en ceci:

#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

Et mes dépendances:

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

Et les annotations utilisées sur la classe de test:

@RunWith(SpringRunner.class)
@DataJpaTest
@ActiveProfiles("test")
public class CommentServicesIntegrationTests {
...
}
1
Georgi Peev
<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>
0
Alex R

Lors de l'ouverture de la console h2, l'URL JDBC doit correspondre à celle spécifiée dans les propriétés:

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

Ce qui semble évident, mais j'ai passé des heures à comprendre cela ..

0
nagy.zsolt.hun

Résolu en créant un nouveau dossier src/test/resources + un fichier application.properties, spécifiant explicitement la création d'une base de test:

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create
0
N.MATHIEU