H2 base de données en mémoire. Table introuvable
J'ai une base de données H2 avec 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 de cette table (vide) en utilisant SELECT * FROM PERSON
. Pour l'instant, donc bon.
Cependant, si je change l'URL en "jdbc:h2:mem:test"
, la seule différence étant que la base de données est maintenant en mémoire seulement, 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 appréciée.
7 réponses
Hbm2ddl ferme la connexion après la création de la table, donc h2 la rejette.
Si votre URL de connexion est configurée 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
Dans ce cas, h2 conservera son contenu tant que la vm vivra.
Je sais que ce n'était pas votre cas mais j'ai eu le même problème car H2 créait les tables avec des noms majuscules puis se comportait en minuscules, même si dans tous les scripts (y compris dans ceux de création) j'ai utilisé des minuscules.
Résolu en ajoutant ;DATABASE_TO_UPPER=false
à l'URL de connexion.
Difficile à 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 s'est terminé, sans échec et sans sortie inattendue. Quelle version de h2 utilisez-vous?
La base de données en mémoire H2 stocke les données en mémoire dans la JVM. Lorsque la JVM se termine, ces données sont perdues.
Je soupçonne 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 essaie de l'insérer dans il:
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, l'une après l'autre, j'ai obtenu le résultat suivant:
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) ...
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'y a pas de table dans laquelle elle peut être insérée.
Quand j'ai changé les chaînes de connexion en jdbc:h2:test
, j'ai trouvé qu'il n'y avait pas une telle erreur. J'ai également trouvé qu'un fichier test.h2.db
était apparu. C'était là que H2 avait mis la table, et comme elle avait été stockée sur le disque, la table était toujours là pour la classe InsertIntoTable à trouver.
, 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é suivant, 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 garder la base de données 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 active, utilisez jdbc: h2: mem: test; DB_CLOSE_DELAY=-1.
Cependant, mon problème était que juste le schéma censé être différentes de celles par défaut. Donc insted d'utiliser
JDBC URL: jdbc:h2:mem:test
Je devais utiliser:
JDBC URL: jdbc:h2:mem:testdb
Alors les tables étaient visibles
Je suis venu à ce post 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, donc la table n'était pas du tout là.
Mon problème était que la structure des dossiers pour les scripts evolution était incorrecte.
À Partir de: https://www.playframework.com/documentation/2.0/Evolutions
Play suit les évolutions de votre base de données à l'aide de plusieurs scripts evolutions. Ces scripts sont écrits en vieux SQL simple et doivent être situés dans le conf/évolutions/{nom de base de données} répertoire de votre application. Si les évolutions s'appliquent à votre base de données par défaut, ce chemin est conf / evolutions / default.
J'ai eu un dossier appelé conf/évolutions.par défaut créé par eclipse. Le problème a disparu après avoir corrigé la structure des dossiers à conf / evolutions / default
<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>