ฉันสามารถสร้างสคีมาอัตโนมัติ 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

ขอบคุณมันทำให้มันทำงานได้ในขณะที่ฉันใช้ชุดการเปลี่ยนแปลงที่สร้างขึ้นจากลิควิดเบสที่ใช้ชื่อสคีมาสำหรับ 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

@ จอห์นนี่แน่ใจเหรอ? ดูเหมือนว่า;ไม่จำเป็นต้องหลบหนี ( ;ก่อนหน้านี้ไม่มีค่า Escape INIT) ลองใช้แบ็กสแลชเดียวได้ไหม 'script1.sql'\;RUNSCRIPT...
Thomas Mueller


18

หากคุณใช้สปริงกับ 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

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 บน Connectionแต่บางครั้งฉันก็สร้างและเติมข้อมูลในโค้ดตามที่แนะนำด้านล่าง

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 เป็นต้น แต่โดยค่าเริ่มต้นคุณจะอยู่ในสคีมาสาธารณะและไม่มีสคีมาตาอื่นอยู่
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;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.