Могу ли я сделать так, чтобы H2 автоматически создавал схему в базе данных в памяти?

96

(Я уже видел базу данных H2 в памяти - схема инициализации через вопрос Spring / Hibernate ; здесь она не применима.)

Я хотел бы знать, есть ли в H2 параметр, который позволит мне автоматически создавать схему при подключении к ней. Если это поможет, меня интересует только случай в памяти.

H2 поддерживает различные модификаторы, разделенные точкой с запятой, в конце URL-адреса, но я не нашел ни одного для автоматического создания схемы. Есть такая особенность?

Лэрд Нельсон
источник

Ответы:

176

Да, H2 поддерживает выполнение операторов SQL при подключении . Вы можете запустить сценарий или просто пару операторов:

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

Обратите внимание, что двойная обратная косая черта ( \\) требуется только в Java. Обратная косая черта перед в ;пределах INITобязательна.

Томас Мюллер
источник
Большое спасибо; Не уверен, как я это пропустил в (отличной) документации.
Laird Nelson
Спасибо, это сработало, так как я использовал сгенерированные наборы изменений из Liquibase, которые используют имя схемы для сгенерированного xml.
Jaime Hablutzel
2
Обратите внимание, что если вы используете H2 с гибернацией и хотите запустить несколько сценариев, вызвав RUNSCRIPT , вам следует ввести тройную обратную косую черту (\\\). Например, вы должны настроить <property name="hibernate.connection.url">jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'script1.sql'\\\;RUNSCRIPT FROM script2.sql'</property>в своей конфигурации гибернации.
Джонни
@Johnny Ты уверен? Похоже, что ;не нужно экранировать ( ;перед символом есть неэкранированный INIT). Не могли бы вы попробовать, если работает только одна обратная косая черта? 'script1.sql'\;RUNSCRIPT...
Томас Мюллер,
1
@pinkpanther, да, см. stackoverflow.com/questions/4490138/…
Томас Мюллер
18

Если вы используете spring с application.yml, для вас подойдет следующее:

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

Маркиз Блаунт
источник
Так же можно создать схему в Grails 3
xtheshadowgod 06
1
Большое спасибо. Я использовал этот совет, чтобы исправить проблему, из-за которой мой код не работал в течение 4 дней.
Deepboy
9

То, что написал Томас, правильно, в дополнение к этому, если вы хотите инициализировать несколько схем, вы можете использовать следующее. Обратите внимание, что \\;два оператора создания разделены.

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

ссылка: http://www.h2database.com/html/features.html#execute_sql_on_connection

Зевс
источник
8

«По умолчанию, когда приложение вызывает, DriverManager.getConnection(url, ...)а база данных, указанная в URL, еще не существует, создается новая (пустая) база данных.» - База данных H2 .

Приложение: @Thomas Mueller показывает, как выполнять SQL при подключении , но иногда я просто создаю и заполняю код, как предлагается ниже.

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);
        }
    }
}
мусорный бог
источник
Да, и это каталог или база данных , а не схема внутри нее. Таким образом, вы можете открыть соединение с jdbc: h2: mem: test, например, но по умолчанию вы помещены в схему PUBLIC, и никаких других схем не существует.
Laird Nelson
1

Если вы используете Spring Framework application.ymlи не можете заставить тест найти файл SQL в INITсвойстве, вы можете использовать classpath:обозначение.

Например, если у вас есть init.sqlфайл SQL src/test/resources, просто используйте :

url=jdbc:h2:~/test;INIT=RUNSCRIPT FROM 'classpath:init.sql';DB_CLOSE_DELAY=-1;
Дерик
источник