Czy mogę mieć możliwość automatycznego tworzenia schematu przez H2 w bazie danych w pamięci?

96

(Widziałem już bazę danych H2 w pamięci - schemat Init za pomocą pytania Spring / Hibernate ; nie ma tutaj zastosowania).

Chciałbym wiedzieć, czy w H2 jest ustawienie, które pozwoli mi automatycznie utworzyć schemat po połączeniu się z nim. Jeśli to pomoże, interesuje mnie tylko przypadek w pamięci.

H2 obsługuje różne modyfikatory oddzielone średnikami na końcu adresu URL, ale nie znalazłem takiego do automatycznego tworzenia schematu. Czy jest taka funkcja?

Laird Nelson
źródło

Odpowiedzi:

176

Tak, H2 obsługuje wykonywanie instrukcji SQL podczas łączenia . Możesz uruchomić skrypt lub po prostu jedną lub dwie instrukcje:

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

Należy pamiętać, że podwójny lewy ukośnik ( \\) jest wymagany tylko w Javie. Ukośnik (-y) odwrotny (-e) przed ;elementem INITjest wymagany.

Thomas Mueller
źródło
Dziękuję Ci bardzo; nie jestem pewien, jak przegapiłem to w (doskonałej) dokumentacji.
Laird Nelson
Dziękuję, zadziałało, ponieważ korzystałem z wygenerowanych zestawów zmian z liquibase, które używają nazwy schematu dla wygenerowanego XML.
Jaime Hablutzel
2
Zauważ, że jeśli używasz H2 z hibernacją i chcesz uruchomić wiele skryptów przez wywołanie RUNSCRIPT , powinieneś wpisać potrójny lewy ukośnik (\\\). Na przykład powinieneś skonfigurować <property name="hibernate.connection.url">jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'script1.sql'\\\;RUNSCRIPT FROM script2.sql'</property>w swojej konfiguracji hibernacji.
Johnny
@Johnny Czy na pewno? Wygląda na ;to, że nie trzeba uciekać ( ;przed znakiem znajduje się znak bez znaczenia INIT). Czy możesz spróbować, jeśli działa tylko jeden lewy ukośnik? 'script1.sql'\;RUNSCRIPT...
Thomas Mueller,
1
@pinkpanther tak, patrz stackoverflow.com/questions/4490138/…
Thomas Mueller
18

Jeśli używasz spring z application.yml, poniższe będą działać dla Ciebie

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

Marquis Blount
źródło
Możliwe jest również stworzenie w ten sposób schematu w Grails 3
xtheshadowgod
1
Dziękuję Ci bardzo. Skorzystałem z tej wskazówki, aby rozwiązać problem, który powodował, że mój kod nie działał przez 4 dni.
Deepboy,
9

To, co napisał Thomas, jest poprawne, oprócz tego, jeśli chcesz zainicjować wiele schematów, możesz użyć następującego. Zwróć uwagę, że \\;dwie instrukcje create są oddzielone.

    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
źródło
8

„Domyślnie, gdy wywołuje się aplikacja, DriverManager.getConnection(url, ...)a baza danych określona w adresie URL jeszcze nie istnieje, tworzona jest nowa (pusta) baza danych.” - Baza danych H2 .

Dodatek: @Thomas Mueller pokazuje, jak wykonać SQL przy połączeniu , ale czasami po prostu tworzę i wypełniam kod, jak zasugerowano poniżej.

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
źródło
Tak, i to jest katalog lub baza danych , a nie schemat w niej. Możesz więc na przykład otworzyć połączenie z jdbc: h2: mem: test, ale domyślnie jesteś umieszczony w schemacie PUBLIC i nie istnieją żadne inne schematy.
Laird Nelson
1

Jeśli używasz Spring Framework z application.ymli masz problem ze znalezieniem przez test pliku SQL we INITwłaściwości, możesz użyć classpath:notacji.

Na przykład, jeśli masz init.sqlplik SQL na src/test/resources, po prostu użyj :

url=jdbc:h2:~/test;INIT=RUNSCRIPT FROM 'classpath:init.sql';DB_CLOSE_DELAY=-1;
Dherik
źródło