Puis-je demander à H2 de créer automatiquement un schéma dans une base de données en mémoire?

93

(J'ai déjà vu la base de données H2 en mémoire - schéma d'initialisation via Spring / Hibernate ; cela n'est pas applicable ici.)

J'aimerais savoir s'il existe un paramètre dans H2 qui me permettra de créer automatiquement un schéma lors de la connexion. Si cela aide, je ne suis intéressé que par le cas en mémoire.

H2 prend en charge divers modificateurs séparés par des points-virgules à la fin de l'URL, mais je n'en ai pas trouvé pour créer automatiquement un schéma. Existe-t-il une telle fonctionnalité?

Laird Nelson
la source

Réponses:

171

Oui, H2 prend en charge l' exécution des instructions SQL lors de la connexion . Vous pouvez exécuter un script, ou simplement une instruction ou deux:

String url = "jdbc:h2:mem:test;" + 
             "INIT=CREATE SCHEMA IF NOT EXISTS TEST"
String url = "jdbc:h2:mem:test;" + 
             "INIT=CREATE SCHEMA IF NOT EXISTS TEST\\;" + 
                  "SET SCHEMA TEST";
String url = "jdbc:h2:mem;" + 
             "INIT=RUNSCRIPT FROM '~/create.sql'\\;" + 
                  "RUNSCRIPT FROM '~/populate.sql'";

Veuillez noter que la double barre oblique inverse ( \\) n'est requise que dans Java. Le (s) backslash (s) avant ;dans le INITest obligatoire.

Thomas Mueller
la source
Merci beaucoup; Je ne sais pas comment j'ai manqué cela dans la (excellente) documentation.
Laird Nelson
Merci, cela a fait le travail car j'utilisais des ensembles de modifications générés à partir de liquibase qui utilisent le nom de schéma pour le xml généré.
Jaime Hablutzel du
2
Notez que si vous utilisez H2 avec hibernate et que vous souhaitez exécuter plusieurs scripts en appelant RUNSCRIPT , vous devez taper une triple barre oblique inverse (\\\). Par exemple, vous devez configurer <property name="hibernate.connection.url">jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'script1.sql'\\\;RUNSCRIPT FROM script2.sql'</property>dans votre configuration d'hibernation.
Johnny
@Johnny Êtes-vous sûr? Il semble que le ;n'a pas besoin d'être échappé (il y a un non échappé ;avant le INIT). Pourriez-vous essayer si l'utilisation d'une seule barre oblique inverse fonctionne? 'script1.sql'\;RUNSCRIPT...
Thomas Mueller
1
@pinkpanther oui, voir stackoverflow.com/questions/4490138/…
Thomas Mueller
14

Si vous utilisez spring avec application.yml, ce qui suit fonctionnera pour vous

spring: datasource: url: jdbc:h2:mem:mydb;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL;INIT=CREATE SCHEMA IF NOT EXISTS calendar

Marquis Blount
la source
Il est également possible de créer un schéma de cette façon dans Grails 3
xtheshadowgod
1
Merci beaucoup. J'ai utilisé cette astuce pour résoudre un problème qui empêchait mon code de fonctionner pendant 4 jours.
Deepboy
9

Ce que Thomas a écrit est correct, en plus de cela, si vous souhaitez initialiser plusieurs schémas, vous pouvez utiliser ce qui suit. Notez qu'il y a une \\;séparation des deux instructions de création.

    EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
                    .setType(EmbeddedDatabaseType.H2)
                    .setName("testDb;DB_CLOSE_ON_EXIT=FALSE;MODE=Oracle;INIT=create " +
                            "schema if not exists " +
                            "schema_a\\;create schema if not exists schema_b;" +
                            "DB_CLOSE_DELAY=-1;")
                    .addScript("sql/provPlan/createTable.sql")
                    .addScript("sql/provPlan/insertData.sql")
                    .addScript("sql/provPlan/insertSpecRel.sql")
                    .build();

réf: http://www.h2database.com/html/features.html#execute_sql_on_connection

Zeus
la source
8

"Par défaut, lorsqu'une application appelle DriverManager.getConnection(url, ...)et que la base de données spécifiée dans l'URL n'existe pas encore, une nouvelle base de données (vide) est créée." - Base de données H2 .

Addendum: @Thomas Mueller montre comment exécuter SQL lors de la connexion , mais parfois je crée et remplis simplement le code, comme suggéré ci-dessous.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

/** @see http://stackoverflow.com/questions/5225700 */
public class H2MemTest {

    public static void main(String[] args) throws Exception {
        Connection conn = DriverManager.getConnection("jdbc:h2:mem:", "sa", "");
        Statement st = conn.createStatement();
        st.execute("create table customer(id integer, name varchar(10))");
        st.execute("insert into customer values (1, 'Thomas')");
        Statement stmt = conn.createStatement();
        ResultSet rset = stmt.executeQuery("select name from customer");
        while (rset.next()) {
            String name = rset.getString(1);
            System.out.println(name);
        }
    }
}
trashgod
la source
Oui, et c'est le catalogue ou la base de données , pas un schéma à l'intérieur. Vous pouvez donc ouvrir une connexion à jdbc: h2: mem: test, par exemple, mais par défaut, vous êtes placé dans le schéma PUBLIC, et aucun autre schéma n'existe.
Laird Nelson
0

Si vous utilisez Spring Framework avec application.ymlet que vous rencontrez des difficultés pour que le test trouve le fichier SQL sur la INITpropriété, vous pouvez utiliser leclasspath: notation.

Par exemple, si vous avez un init.sqlfichier SQL sur le src/test/resources, utilisez simplement :

url=jdbc:h2:~/test;INIT=RUNSCRIPT FROM 'classpath:init.sql';DB_CLOSE_DELAY=-1;
Dherik
la source