Posso fare in modo che H2 crei automaticamente uno schema in un database in memoria?


93

(Ho già visto il database H2 In memoria - Schema di inizializzazione tramite domanda Spring / Hibernate ; non è applicabile qui.)

Mi piacerebbe sapere se c'è un'impostazione in H2 che mi consentirà di creare automaticamente uno schema al momento della connessione ad esso. Se aiuta, mi interessa solo il caso in memoria.

H2 supporta vari modificatori separati da punto e virgola alla fine dell'URL, ma non ne ho trovato uno per la creazione automatica di uno schema. C'è una tale caratteristica?

Risposte:


172

Sì, H2 supporta l' esecuzione di istruzioni SQL durante la connessione . Potresti eseguire uno script o solo una o due istruzioni:

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'";

Si noti che la doppia barra rovesciata ( \\) è richiesta solo in Java. La barra rovesciata prima ;all'interno di INITè obbligatoria.


Grazie mille; non sono sicuro di come mi sia sfuggito nella (eccellente) documentazione.
Laird Nelson

Grazie, ha funzionato mentre stavo usando i changeset generati da liquibase che usano il nome dello schema per l'xml generato.
Jaime Hablutzel

2
Nota che se usi H2 con ibernazione e desideri eseguire più script chiamando RUNSCRIPT , devi digitare tripla barra rovesciata (\\\). Ad esempio, dovresti impostare <property name="hibernate.connection.url">jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'script1.sql'\\\;RUNSCRIPT FROM script2.sql'</property>nella tua configurazione di ibernazione.
Johnny

@Johnny Sei sicuro? Sembra che ;non sia necessario eseguire l'escape (c'è un unescaped ;prima di INIT). Potresti provare se usare solo una barra rovesciata funziona? 'script1.sql'\;RUNSCRIPT...
Thomas Mueller

1
@pinkpanther affermativo, vedere stackoverflow.com/questions/4490138/...
Thomas Mueller

14

Se stai usando la molla con application.yml, quanto segue funzionerà per te

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


È anche possibile creare uno schema in questo modo in Grails 3
xtheshadowgod

1
Grazie mille. Ho usato questo suggerimento per risolvere un problema che impediva al mio codice di funzionare per 4 giorni.
Deepboy

9

Ciò che Thomas ha scritto è corretto, in aggiunta a ciò, se vuoi inizializzare più schemi puoi usare quanto segue. Nota che c'è una \\;separazione tra le due istruzioni create.

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

rif: http://www.h2database.com/html/features.html#execute_sql_on_connection


8

"Per impostazione predefinita, quando un'applicazione chiama DriverManager.getConnection(url, ...)e il database specificato nell'URL non esiste ancora, viene creato un nuovo database (vuoto)." - H2 Database .

Addendum: @Thomas Mueller mostra come eseguire SQL su Connection , ma a volte creo e inserisco semplicemente il codice, come suggerito di seguito.

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

Sì, e questo è il catalogo o il database , non uno schema al suo interno. Quindi potresti aprire una connessione a jdbc: h2: mem: test, ad esempio, ma per impostazione predefinita sei inserito nello schema PUBLIC e non esistono altri schemi.
Laird Nelson

0

Se stai usando Spring Framework con application.ymle hai problemi a fare in modo che il test trovi il file SQL sulla INITproprietà, puoi usare la classpath:notazione.

Ad esempio, se hai un init.sqlfile SQL su src/test/resources, usa semplicemente :

url=jdbc:h2:~/test;INIT=RUNSCRIPT FROM 'classpath:init.sql';DB_CLOSE_DELAY=-1;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.