Posso fazer com que o H2 crie automaticamente um esquema em um banco de dados na memória?

93

(Eu já vi o banco de dados H2 na memória - esquema de inicialização via questão Spring / Hibernate ; não é aplicável aqui.)

Gostaria de saber se há uma configuração em H2 que me permitirá criar automaticamente um esquema ao me conectar a ele. Se ajudar, estou interessado apenas no caso da memória.

H2 oferece suporte a vários modificadores separados por ponto-e-vírgula no final da URL, mas não encontrei um para criar automaticamente um esquema. Existe esse recurso?

Laird Nelson
fonte

Respostas:

170

Sim, H2 suporta a execução de instruções SQL durante a conexão . Você pode executar um script ou apenas uma ou duas instruções:

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

Observe que a barra invertida dupla ( \\) só é necessária no Java. A barra invertida (es) antes ;dentro do INITé necessária.

Thomas Mueller
fonte
Muito obrigado; não tenho certeza de como perdi isso na documentação (excelente).
Laird Nelson,
Obrigado, funcionou porque eu estava usando conjuntos de alterações gerados a partir de liquibase que usam o nome do esquema para xml gerado.
Jaime Hablutzel
2
Observe que se você usar H2 com hibernação e quiser executar vários scripts chamando RUNSCRIPT , deverá digitar barra invertida tripla (\\\). Por exemplo, você deve definir <property name="hibernate.connection.url">jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'script1.sql'\\\;RUNSCRIPT FROM script2.sql'</property>em sua configuração de hibernação.
Johnny
@Johnny Tem certeza? Parece que o ;não precisa ter escape (há um sem escape ;antes do INIT). Você poderia tentar se usar apenas uma barra invertida funciona? 'script1.sql'\;RUNSCRIPT...
Thomas Mueller
1
@pinkpanther sim, consulte stackoverflow.com/questions/4490138/…
Thomas Mueller
14

Se você estiver usando spring com application.yml, o seguinte funcionará para você

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

Marquês Blount
fonte
Também é possível criar um esquema desta forma em Grails 3
xtheshadowgod
1
Muito obrigado. Usei essa dica para corrigir um problema que estava fazendo com que meu código não funcionasse por 4 dias.
Deepboy
9

O que Thomas escreveu está correto, além disso, se você deseja inicializar vários esquemas, pode usar o seguinte. Observe que há uma \\;separação das duas instruções de criação.

    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
fonte
8

"Por padrão, quando um aplicativo chama DriverManager.getConnection(url, ...)e o banco de dados especificado na URL ainda não existe, um novo banco de dados (vazio) é criado." - H2 Database .

Adendo: @Thomas Mueller mostra como executar SQL na conexão , mas às vezes eu apenas crio e preencheu o código, conforme sugerido abaixo.

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);
        }
    }
}
deus do lixo
fonte
Sim, e esse é o catálogo ou banco de dados , não um esquema dentro dele. Portanto, você pode abrir uma conexão com jdbc: h2: mem: test, por exemplo, mas por padrão você é colocado no esquema PUBLIC e nenhum outro esquema existe.
Laird Nelson,
0

Se você estiver usando o Spring Framework application.ymle tiver problemas para fazer o teste localizar o arquivo SQL na INITpropriedade, pode usar a classpath:notação.

Por exemplo, se você tiver um init.sqlarquivo SQL no src/test/resources, basta usar :

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