1. 引言

H2数据库引擎是基于Java的流行开源数据库。在这个简短的教程中,我们将学习如何在连接H2内存数据库时自动创建模式。

2. 什么是H2?

H2数据库引擎是一个基于Java的SQL和JDBC兼容的数据库。 它有一些与其他关系型数据库不同的特性:

  • 存储:它可以作为纯内存数据库或使用文件系统运行。
  • 模式:以独立服务器或嵌入到其他应用程序中运行。

这些特性使H2成为开发和测试的理想选择。然而,由于其临时性质,它也可能带来一些挑战。

当连接到H2内存数据库时,可能不存在模式。 这是因为内存数据库是临时的,只有当它们所在的程序运行时才存在。一旦应用程序终止,内存数据库的所有内容都将丢失。

接下来,我们将探讨几种初始化H2内存数据库的方法。

3. 在H2中自动创建模式

对于H2内存数据库,有多种方法可以自动创建模式。每种方法都有其优缺点,选择哪种取决于多个因素。

3.1. 基于Java

下面的示例展示了如何使用纯Java代码和JDBC初始化内存H2数据库。这对于不使用Spring或其他提供数据库连接的框架的应用程序是一个不错的选择:

Connection conn = DriverManager.getConnection(
  "jdbc:h2:mem:baeldung;INIT=CREATE SCHEMA IF NOT EXISTS baeldung",
  "admin",
  "password");

在上述示例中,我们使用连接URL指定要创建的模式。 我们还可以传递额外的命令来进一步初始化数据库:

Connection conn = DriverManager.getConnection(
  "jdbc:h2:mem:baeldung;INIT=CREATE SCHEMA IF NOT EXISTS baeldung\\;SET SCHEMA baeldung;CREATE TABLE users (name VARCHAR(100) NOT NULL, email VARCHAR(100) NOT NULL);",
  "admin",
  "password");

由于所有这些命令可能会使URL难以阅读,H2还支持通过引用SQL文件初始化内存数据库。 首先,我们创建包含初始化语句的文件:

CREATE SCHEMA IF NOT EXISTS baeldung;
SET SCHEMA baeldung;
CREATE TABLE users (name VARCHAR(100) NOT NULL, email VARCHAR(100) NOT NULL);

然后,我们可以使用稍有不同的连接URL引用文件:

Connection conn = DriverManager.getConnection(
  "jdbc:h2:mem:baeldung;INIT=RUNSCRIPT FROM 'h2init.sql';",
  "admin",
  "password");

3.2. Spring Boot

在使用Spring Boot应用程序时,我们也可以利用熟悉的Spring数据属性来初始化H2内存数据库。

首先,我们可以像上面一样,在URL本身中提供所有初始化语句。我们首先定义H2数据源的Spring属性:

spring.datasource.url=jdbc:h2:mem:baeldung;INIT=CREATE SCHEMA IF NOT EXISTS baeldung\\;SET SCHEMA baeldung;

然后,我们可以像正常应用程序那样使用默认的DataSourcebean:

public void initDatabaseUsingSpring(@Autowired DataSource ds) {
    try (Connection conn = ds.getConnection()) {
        conn.createStatement().execute("create table users (name VARCHAR(100) NOT NULL, email VARCHAR(100) NOT NULL);");
        conn.createStatement().execute("insert into users (name, email) values ('Mike', '[email protected]')");
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

与纯Java代码类似,我们也可以在连接URL中引用包含所有初始化语句的SQL文件。我们只需要更新我们的属性:

spring.datasource.url=jdbc:h2:mem:baeldung;INIT=RUNSCRIPT FROM 'src/main/resources/h2init.sql';

值得注意的是,H2不会通过Spring Boot加载资源。 因此,我们必须在应用运行的实际上下文中引用文件路径。

现在,我们可以像以前一样使用DataSource,而无需先初始化模式:

private void initDatabaseUsingSpring(@Autowired DataSource ds) {
    try (Connection conn = ds.getConnection()) {
        conn.createStatement().execute("insert into users (name, email) values ('Mike', '[email protected]')");
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

最后,当使用Spring Boot时,我们还可以利用SQL初始化模式,而不依赖H2的功能。我们只需将初始化文件重命名为data.sql,并稍微调整属性:

spring.datasource.url=jdbc:h2:mem:baeldung
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=admin
spring.datasource.password=password
spring.sql.init.mode=embedded

需要注意的是,我们的属性并未提及模式或初始化文件。

3.3. Spring XML

此外,如果我们使用纯Spring XML配置DataSource,我们也可以在那里包含初始化语句。

让我们看看如何创建模式:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="org.h2.Driver"/>
    <property name="url" value="jdbc:h2:mem:testdb;INIT=CREATE SCHEMA IF NOT EXISTS baeldung\\;SET SCHEMA baeldung;"/>
    <property name="username" value="admin"/>
    <property name="password" value="password"/>
</bean>

如前所见,URL中有多个初始化语句可能会使其难以阅读。因此,最好将它们放入单个SQL文件中,并在URL中引用该文件:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="org.h2.Driver"/>
    <property name="url" value="jdbc:h2:mem:testdb;INIT=RUNSCRIPT FROM 'src/main/resources/h2init.sql';"/>
    <property name="username" value="admin"/>
    <property name="password" value="password"/>
</bean>

4. 总结

H2内存数据库是Java开发者常用的内存和嵌入式数据库选项之一。由于其速度快、占用资源少,非常适合用于软件测试和自动化管道等场景。

在这篇文章中,我们看到了几种确保在应用程序启动时我们的H2内存数据库自动初始化并准备好查询的方法。无论我们使用纯JDBC还是Spring框架,只需几行配置,我们就可以确保内存数据库在启动时完全初始化并可供使用。

如往常一样,上述代码示例可以在GitHub上找到。