Kann H2 ein Schema in einer In-Memory-Datenbank automatisch erstellen lassen?

93

(Ich habe bereits die H2-Datenbank im Speicher gesehen - Init-Schema über Spring / Hibernate- Frage; sie ist hier nicht anwendbar.)

Ich möchte wissen, ob es in H2 eine Einstellung gibt, mit der ich beim Herstellen einer Verbindung automatisch ein Schema erstellen kann. Wenn es hilft, interessiert mich nur der In-Memory-Fall.

H2 unterstützt verschiedene durch Semikolons getrennte Modifikatoren am Ende der URL, aber ich habe keinen gefunden, um automatisch ein Schema zu erstellen. Gibt es eine solche Funktion?

Laird Nelson
quelle

Antworten:

170

Ja, H2 unterstützt die Ausführung von SQL-Anweisungen beim Herstellen einer Verbindung . Sie könnten ein Skript oder nur eine oder zwei Anweisungen ausführen:

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

Bitte beachten Sie, dass der doppelte Backslash ( \\) nur in Java erforderlich ist. Der / die Backslash (s) vor ;dem INITist erforderlich.

Thomas Müller
quelle
Vielen Dank; Ich bin mir nicht sicher, wie ich das in der (ausgezeichneten) Dokumentation verpasst habe.
Laird Nelson
Vielen Dank, es hat funktioniert, da ich generierte Änderungssätze aus liquibase verwendet habe, die den Schemanamen für generierte XML verwenden.
Jaime Hablutzel
2
Beachten Sie, dass Sie Triple Backslash (\\\) eingeben sollten , wenn Sie H2 im Ruhezustand verwenden und mehrere Skripts durch Aufrufen von RUNSCRIPT ausführen möchten . Sie sollten beispielsweise <property name="hibernate.connection.url">jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'script1.sql'\\\;RUNSCRIPT FROM script2.sql'</property>Ihre Konfiguration für den Ruhezustand einrichten .
Johnny
@ Johnny Bist du sicher? Es sieht so aus, als ;müsste das nicht entkommen (es gibt ein Unescaped ;vor dem INIT). Könnten Sie versuchen, ob nur ein Backslash funktioniert? 'script1.sql'\;RUNSCRIPT...
Thomas Mueller
1
@pinkpanther ja, siehe stackoverflow.com/questions/4490138/…
Thomas Mueller
14

Wenn Sie spring mit application.yml verwenden, funktioniert Folgendes für Sie

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

Marquis Blount
quelle
Es ist auch möglich, ein Schema auf diese Weise in Grails 3
xtheshadowgod
1
Vielen Dank. Ich habe diesen Tipp verwendet, um ein Problem zu beheben, das dazu führte, dass mein Code 4 Tage lang nicht funktionierte.
Deepboy
9

Was Thomas geschrieben hat, ist außerdem korrekt. Wenn Sie mehrere Schemas initialisieren möchten, können Sie Folgendes verwenden. Beachten Sie, dass \\;die beiden Anweisungen create getrennt sind.

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

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

Zeus
quelle
8

"Wenn eine Anwendung aufruft DriverManager.getConnection(url, ...)und die in der URL angegebene Datenbank noch nicht vorhanden ist, wird standardmäßig eine neue (leere) Datenbank erstellt." - H2-Datenbank .

Nachtrag: @Thomas Mueller zeigt, wie SQL bei Verbindung ausgeführt wird , aber manchmal erstelle und fülle ich den Code einfach ein, wie unten vorgeschlagen.

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);
        }
    }
}
Müllgott
quelle
Ja, und das ist der Katalog oder die Datenbank , kein Schema darin. Sie können beispielsweise eine Verbindung zu jdbc: h2: mem: test herstellen, aber standardmäßig werden Sie in das PUBLIC-Schema eingefügt, und es sind keine anderen Schemata vorhanden.
Laird Nelson
0

Wenn Sie Spring Framework mit verwenden application.ymlund Probleme haben, den Test dazu zu bringen, die SQL-Datei in der INITEigenschaft zu finden, können Sie die classpath:Notation verwenden.

Wenn Sie beispielsweise eine init.sqlSQL-Datei auf der haben src/test/resources, verwenden Sie einfach :

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