Tôi có thể có H2 tự động tạo một lược đồ trong cơ sở dữ liệu trong bộ nhớ không?


93

(Tôi đã thấy cơ sở dữ liệu H2 Trong bộ nhớ - Lược đồ Init thông qua câu hỏi Spring / Hibernate ; nó không áp dụng ở đây.)

Tôi muốn biết liệu có cài đặt nào trong H2 cho phép tôi tự động tạo một lược đồ khi kết nối với nó hay không. Nếu nó hữu ích, tôi chỉ quan tâm đến trường hợp trong bộ nhớ.

H2 hỗ trợ nhiều công cụ sửa đổi được phân tách bằng dấu chấm phẩy ở cuối URL, nhưng tôi không tìm thấy công cụ sửa đổi nào để tự động tạo giản đồ. Có một tính năng như vậy?

Câu trả lời:


171

Có, H2 hỗ trợ thực thi các câu lệnh SQL khi kết nối . Bạn có thể chạy một tập lệnh hoặc chỉ một hoặc hai câu lệnh:

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

Xin lưu ý rằng dấu gạch chéo ngược kép ( \\) chỉ được yêu cầu trong Java. (Các) dấu gạch chéo ngược trước ;bên trong INITlà bắt buộc.


Cảm ơn rât nhiều; không chắc làm thế nào tôi đã bỏ lỡ điều đó trong tài liệu (tuyệt vời).
Laird Nelson

Cảm ơn bạn, nó đã thành công như tôi đang sử dụng các tập thay đổi được tạo từ liquibase sử dụng tên lược đồ cho xml được tạo.
Jaime Hablutzel,

2
Lưu ý rằng nếu bạn sử dụng H2 với chế độ ngủ đông và muốn chạy nhiều tập lệnh bằng cách gọi RUNSCRIPT , bạn nên nhập dấu gạch chéo ngược ba (\\\). Ví dụ: bạn nên thiết lập <property name="hibernate.connection.url">jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'script1.sql'\\\;RUNSCRIPT FROM script2.sql'</property>trong cấu hình ngủ đông của mình.
Johnny

@Johnny Bạn có chắc không? Có vẻ như ;không cần phải thoát (có một không thoát ;trước INIT). Bạn có thể thử nếu chỉ sử dụng một dấu gạch chéo ngược có hiệu quả không? 'script1.sql'\;RUNSCRIPT...
Thomas Mueller


14

Nếu bạn đang sử dụng spring với application.yml, phần sau sẽ phù hợp với bạn

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


Cũng có thể tạo giản đồ theo cách này trong Grails 3
xtheshadowgod

1
Cảm ơn rât nhiều. Tôi đã sử dụng mẹo này để khắc phục sự cố khiến mã của tôi không hoạt động trong 4 ngày.
Deepboy 11/09/18

9

Những gì Thomas đã viết là đúng, ngoài ra, nếu bạn muốn khởi tạo nhiều lược đồ, bạn có thể sử dụng cách sau. Lưu ý rằng có một \\;ngăn cách giữa hai câu lệnh tạ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


8

"Theo mặc định, khi một ứng dụng gọi DriverManager.getConnection(url, ...)và cơ sở dữ liệu được chỉ định trong URL chưa tồn tại, một cơ sở dữ liệu mới (trống) sẽ được tạo." - H2 Database .

Phụ lục: @Thomas Mueller chỉ ra cách Thực thi SQL trên Kết nối , nhưng đôi khi tôi chỉ tạo và điền vào mã, như đề xuất bên dưới.

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

Có, và đó là danh mục hoặc cơ sở dữ liệu , không phải là một lược đồ bên trong nó. Vì vậy, bạn có thể mở một kết nối tới jdbc: h2: mem: test chẳng hạn, nhưng theo mặc định, bạn được đặt trong lược đồ PUBLIC và không tồn tại schemata nào khác.
Laird Nelson

0

Nếu bạn đang sử dụng Spring Framework với application.ymlvà gặp sự cố khi thực hiện kiểm tra tìm tệp SQL trên thuộc INITtính, bạn có thể sử dụng classpath:ký hiệu.

Ví dụ: nếu bạn có init.sqltệp SQL trên src/test/resources, chỉ cần sử dụng :

url=jdbc:h2:~/test;INIT=RUNSCRIPT FROM 'classpath:init.sql';DB_CLOSE_DELAY=-1;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.