¿Puedo hacer que H2 cree automáticamente un esquema en una base de datos en memoria?

93

(Ya he visto la base de datos H2 en la memoria: esquema de inicio a través de la pregunta Spring / Hibernate ; no es aplicable aquí).

Me gustaría saber si hay una configuración en H2 que me permita crear automáticamente un esquema al conectarme a él. Si ayuda, solo me interesa el caso en memoria.

H2 admite varios modificadores separados por punto y coma al final de la URL, pero no encontré ninguno para crear automáticamente un esquema. ¿Existe tal característica?

Laird Nelson
fuente

Respuestas:

172

Sí, H2 admite la ejecución de sentencias SQL al conectarse . Puede ejecutar un script o solo una declaración o dos:

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

Tenga en cuenta que la doble barra invertida ( \\) solo es necesaria en Java. Se requiere la barra invertida (s) antes de ;dentro de INIT.

Thomas Mueller
fuente
Muchas gracias; No estoy seguro de cómo me perdí eso en la (excelente) documentación.
Laird Nelson
Gracias, hizo el trabajo ya que estaba usando conjuntos de cambios generados de liquibase que usan el nombre de esquema para xml generado.
Jaime Hablutzel
2
Tenga en cuenta que si usa H2 con hibernación y desea ejecutar varios scripts llamando a RUNSCRIPT , debe escribir triple barra invertida (\\\). Por ejemplo, debe realizar la configuración <property name="hibernate.connection.url">jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'script1.sql'\\\;RUNSCRIPT FROM script2.sql'</property>en su configuración de hibernación.
Johnny
@Johnny ¿Estás seguro? Parece que ;no es necesario escapar (hay un sin escapar ;antes de INIT). ¿Podría intentarlo si usar solo una barra invertida funciona? 'script1.sql'\;RUNSCRIPT...
Thomas Mueller
1
@pinkpanther sí, consulte stackoverflow.com/questions/4490138/…
Thomas Mueller
14

Si está utilizando spring con application.yml, lo siguiente funcionará para usted

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

Marqués Blount
fuente
También es posible crear un esquema de esta manera en Grails 3
xtheshadowgod
1
Muchas gracias. Utilicé este consejo para solucionar un problema que provocaba que mi código no funcionara durante 4 días.
Deepboy
9

Lo que Thomas ha escrito es correcto, además de eso, si desea inicializar múltiples esquemas, puede usar lo siguiente. Tenga en cuenta que hay una \\;separación de las dos declaraciones de creación.

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

"De forma predeterminada, cuando una aplicación llama DriverManager.getConnection(url, ...)y la base de datos especificada en la URL aún no existe, se crea una nueva base de datos (vacía)". - Base de datos H2 .

Anexo: @Thomas Mueller muestra cómo ejecutar SQL en la conexión , pero a veces solo creo y completo el código, como se sugiere a continuación.

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);
        }
    }
}
basurero
fuente
Sí, y ese es el catálogo o la base de datos , no un esquema dentro de él. Por lo tanto, puede abrir una conexión a jdbc: h2: mem: test, por ejemplo, pero de forma predeterminada se le coloca en el esquema PUBLIC y no existe ningún otro esquema.
Laird Nelson
0

Si está utilizando Spring Framework application.ymly tiene problemas para hacer que la prueba encuentre el archivo SQL en la INITpropiedad, puede usar la classpath:notación.

Por ejemplo, si tiene un init.sqlarchivo SQL en el src/test/resources, simplemente use :

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