ฐานข้อมูลในหน่วยความจำ H2 ไม่พบตาราง


184

"jdbc:h2:test"ฉันมีฐานข้อมูลที่มี URL H2 CREATE TABLE PERSON (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(64), LASTNAME VARCHAR(64));ฉันสร้างตารางโดยใช้ จากนั้นผมก็เลือกทุกอย่างจากนี้ (ว่าง) SELECT * FROM PERSONโดยใช้ตาราง จนถึงตอนนี้ดีมาก

อย่างไรก็ตามถ้าฉันเปลี่ยน URL เป็น"jdbc:h2:mem:test"ความแตกต่างเพียงอย่างเดียวของฐานข้อมูลที่อยู่ในหน่วยความจำเท่านั้นนี่ทำให้ฉันorg.h2.jdbc.JdbcSQLException: Table "PERSON" not found; SQL statement: SELECT * FROM PERSON [42102-154]ได้ ฉันอาจจะพลาดอะไรง่ายๆที่นี่ แต่ความช่วยเหลือจะได้รับการชื่นชม


2
หลังจากเปลี่ยนเป็นโหมดในหน่วยความจำคุณจะต้องสร้างตารางPersonอีกครั้ง H2 ไม่รู้อะไรเกี่ยวกับฐานข้อมูลที่คุณสร้างบนดิสก์มาก่อน
Benjamin Muschko

ส่วนที่เหลือของโปรแกรมไม่เปลี่ยนแปลง - ฉันสร้างตารางอีกครั้ง
Jorn

คำตอบ:


332

DB_CLOSE_DELAY=-1

hbm2ddl ปิดการเชื่อมต่อหลังจากสร้างตารางดังนั้น h2 จะยกเลิกการเชื่อมต่อ

หากคุณมี URL การเชื่อมต่อของคุณกำหนดค่าไว้เช่นนี้

jdbc:h2:mem:test

เนื้อหาของฐานข้อมูลจะหายไปในขณะที่การเชื่อมต่อล่าสุดถูกปิด

หากคุณต้องการเก็บเนื้อหาของคุณคุณต้องกำหนดค่า URL เช่นนี้

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

หากทำเช่นนั้นh2จะเก็บเนื้อหาไว้ตราบเท่าที่vmยังมีชีวิตอยู่

สังเกตุเครื่องหมายอัฒภาค ( ;) มากกว่าเครื่องหมายโคลอน ( :)

ดูส่วนฐานข้อมูลในหน่วยความจำของหน้าคุณสมบัติ อ้างถึง:

โดยค่าเริ่มต้นการปิดการเชื่อมต่อล่าสุดไปยังฐานข้อมูลจะปิดฐานข้อมูล สำหรับฐานข้อมูลในหน่วยความจำหมายความว่าเนื้อหาหายไป หากต้องการให้ฐานข้อมูลเปิดอยู่ให้เพิ่ม;DB_CLOSE_DELAY=-1ไปยัง URL ฐานข้อมูล jdbc:h2:mem:test;DB_CLOSE_DELAY=-1เพื่อให้เนื้อหาของฐานข้อมูลในหน่วยความจำตราบใดที่เครื่องเสมือนมีชีวิตอยู่การใช้งาน


ฉันพบปัญหาด้วยตัวเองในเวลาเฉลี่ย แต่ใช่มันถูกต้องทั้งหมด ขอบคุณ!
Jorn

3
และจะต้องมีชื่อฐานข้อมูลในหน่วยความจำคือjdbc:h2:mem:;DB_CLOSE_DELAY=-1ไม่ทำงาน
Peter Becker

เราจะเก็บข้อมูลในไฟล์แทนหน่วยความจำได้อย่างไร
Suleman khan

9
ถ้าคุณใช้ตัวพิมพ์เล็กสำหรับตั้งชื่อตารางของคุณในรหัสคุณควรรู้ว่า H2 เป็นตัวพิมพ์ใหญ่ทุกอย่างโดยค่าเริ่มต้นใช้ DATABASE_TO_UPPER = false เพื่อหลีกเลี่ยงเช่น jdbc: h2: mem: test; DB_CLOSE_DELAY = -1; DATABASE_TO_UPPER = false;
Oleksandr Petrenko

@OleksandrPetrenko - ส่วนท้ายนั้น ';' ดูเหมือนว่าจะทำให้เกิดปัญหา ฉันคิดว่าคุณต้องออกไป
Volksman

104

ฉันรู้ว่านี่ไม่ใช่กรณีของคุณ แต่ฉันมีปัญหาเดียวกันเพราะ H2 กำลังสร้างตารางที่มีชื่อชื่อ UPPERCASE แล้วจะต้องคำนึงถึงตัวอักษรตัวพิมพ์เล็กและตัวพิมพ์ใหญ่แม้ว่าในสคริปต์ทั้งหมด

แก้ไขโดยเพิ่ม;DATABASE_TO_UPPER=falseลงใน URL การเชื่อมต่อ


7
ว้าว - ฉันดีใจมากที่คุณแบ่งปันสิ่งนี้! จะไม่ได้คิดว่า
ms-tg

1
ไม่ใช่วิธีแก้ปัญหาสำหรับคำถามที่ถาม แต่วิธีแก้ปัญหาที่ฉันพบเมื่อค้นหาด้วยคำถามเดียวกัน!
Yaytay

เป็นไปได้ไหมที่ตั้งDATABASE_TO_UPPER=falseสิ่งนี้เป็นคำสั่ง SQL ในสคริปต์เริ่มต้น? (คล้ายกันกับคำสั่งเช่นSET MODE PostgreSQL;) ถ้าเป็นเช่นนั้นไวยากรณ์ที่แน่นอนคืออะไร?
Jonik

3
ฉันจะโหวตได้หลายครั้งได้อย่างไร ขอบคุณมาก! นี่ควรเป็นส่วนหนึ่งของคำตอบแรก
Ribesg

11

ยากที่จะบอก ฉันสร้างโปรแกรมเพื่อทดสอบสิ่งนี้:

package com.gigaspaces.compass;

import org.testng.annotations.Test;

import java.sql.*;

public class H2Test {
@Test
public void testDatabaseNoMem() throws SQLException {
    testDatabase("jdbc:h2:test");
}
@Test
public void testDatabaseMem() throws SQLException {
    testDatabase("jdbc:h2:mem:test");
}

private void testDatabase(String url) throws SQLException {
    Connection connection= DriverManager.getConnection(url);
    Statement s=connection.createStatement();
    try {
    s.execute("DROP TABLE PERSON");
    } catch(SQLException sqle) {
        System.out.println("Table not found, not dropping");
    }
    s.execute("CREATE TABLE PERSON (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(64), LASTNAME VARCHAR(64))");
    PreparedStatement ps=connection.prepareStatement("select * from PERSON");
    ResultSet r=ps.executeQuery();
    if(r.next()) {
        System.out.println("data?");
    }
    r.close();
    ps.close();
    s.close();
    connection.close();
}
}

การทดสอบดำเนินไปจนเสร็จสมบูรณ์โดยไม่มีข้อผิดพลาดและไม่มีเอาต์พุตที่ไม่คาดคิด คุณกำลังใช้ h2 รุ่นใดอยู่


ฉันจะลองวันนี้ขอบคุณ รุ่น H2 เป็นหนึ่งผมได้ปิดเว็บไซต์วันนี้: 1.3.154
Jorn

1
ฉันคิดว่าฉันพบปัญหา เมื่อฉันปิดการเชื่อมต่อตารางถูกสร้างขึ้นด้วยจากนั้นเปิดขึ้นใหม่ฐานข้อมูลหายไป เมื่อฉันเปิดการเชื่อมต่อใหม่ก่อนที่จะปิดการเชื่อมต่อก่อนหน้าข้อมูลยังคงอยู่ เมื่อฉันใช้ไฟล์ข้อมูล (ชัด) จะยังคงอยู่เสมอ
Jorn

7

ฐานข้อมูลในหน่วยความจำ H2 จะเก็บข้อมูลในหน่วยความจำภายใน JVM เมื่อ JVM ออกจากข้อมูลนี้จะหายไป

ฉันสงสัยว่าสิ่งที่คุณกำลังทำนั้นคล้ายกับคลาส Java สองคลาสด้านล่าง หนึ่งในคลาสเหล่านี้สร้างตารางและอีกอันพยายามแทรกลงใน:

import java.sql.*;

public class CreateTable {
    public static void main(String[] args) throws Exception {
        DriverManager.registerDriver(new org.h2.Driver());
        Connection c = DriverManager.getConnection("jdbc:h2:mem:test");
        PreparedStatement stmt = c.prepareStatement("CREATE TABLE PERSON (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(64), LASTNAME VARCHAR(64))");
        stmt.execute();
        stmt.close();
        c.close();
    }
}

และ

import java.sql.*;

public class InsertIntoTable {
    public static void main(String[] args) throws Exception {
        DriverManager.registerDriver(new org.h2.Driver());
        Connection c = DriverManager.getConnection("jdbc:h2:mem:test");
        PreparedStatement stmt = c.prepareStatement("INSERT INTO PERSON (ID, FIRSTNAME, LASTNAME) VALUES (1, 'John', 'Doe')");
        stmt.execute();
        stmt.close();
        c.close();
    }
}

เมื่อฉันรันคลาสเหล่านี้ทีละรายการฉันได้ผลลัพธ์ต่อไปนี้:

C: \ Users \ Luke \ stuff> java CreateTable

C: \ Users \ Luke \ stuff> java InsertIntoTable
ข้อยกเว้นในเธรด "main" org.h2.jdbc.JdbcSQLException: ไม่พบตาราง "PERSON" คำสั่ง SQL:
INSERT INTO PERSON (ID, FIRSTNAME, LASTNAME) ค่า (1, 'John', 'Doe') [42102-154]
        ที่ org.h2.message.DbException.getJdbcSQLException (DbException.java:327)
        ที่ org.h2.message.DbException.get (DbException.java:167)
        ที่ org.h2.message.DbException.get (DbException.java:144)
        ...

ทันทีที่javaกระบวนการแรกออกจากตารางที่สร้างขึ้นโดยCreateTableไม่มีอยู่อีกต่อไป ดังนั้นเมื่อคลาส InsertIntoTable มาพร้อมจะไม่มีตารางให้แทรก

เมื่อฉันเปลี่ยนสตริงการเชื่อมต่อเป็นjdbc:h2:testฉันพบว่าไม่มีข้อผิดพลาดดังกล่าว ฉันยังพบว่ามีไฟล์test.h2.dbปรากฏขึ้น นี่คือที่ H2 วางตารางและเนื่องจากมันถูกเก็บไว้ในดิสก์ตารางจึงยังคงมีคลาส InsertIntoTable เพื่อค้นหา


1
โปรดทราบว่าการregisterDriver()โทรไม่จำเป็น: ก่อนอื่น: Class.forName () ที่เรียบง่ายจะเหมือนกันสำหรับไดรเวอร์ JDBC ส่วนใหญ่และ (ที่สำคัญกว่า) มันไม่จำเป็นอย่างสมบูรณ์สำหรับ Java 6 und up ซึ่งตรวจจับอัตโนมัติ (เข้ากันได้) ไดรเวอร์ JDBC บน classpath
Joachim Sauer

ในหน่วยความจำ db มีอยู่ตราบใดที่โปรแกรมที่เป็นเจ้าของหน่วยความจำทำงานอยู่? ว้าวฉันไม่มีความคิด> _ <แต่จริง ๆ แล้วฉันรู้ว่าฉันกำลังพยายามทำอะไร อ่านคำตอบของคุณฉันไม่แน่ใจว่าคุณทำ
Jorn

2
@ จอน: ฉันอาจไม่รู้ว่าคุณกำลังพยายามทำอะไรฉันคาดเดาจากข้อมูลที่คุณให้ อาจเป็นประโยชน์มากกว่าที่จะให้ SSCCE ( sscce.org ) แสดงให้เห็นถึงปัญหาของคุณ - ฉันจะไม่เรียกคำถามของคุณว่า "สมบูรณ์" ในแง่นั้น ฉันให้คำตอบข้างต้นเพราะมีคนใน SO (ผู้มาใหม่เพื่อการเขียนโปรแกรมส่วนใหญ่) ที่อาจคิดว่าฐานข้อมูล 'ในหน่วยความจำ' เก็บข้อมูลในหน่วยความจำของคอมพิวเตอร์ที่ไหนสักแห่งที่มันสามารถอยู่รอดได้ระหว่างการเรียกใช้โปรแกรม คำถามของคุณไม่สมบูรณ์เพียงพอที่จะโน้มน้าวใจฉันว่าคุณไม่ใช่คนเหล่านี้
ลุควู้ดเวิร์ด

5

ฉันพยายามเพิ่ม

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

อย่างไรก็ตามนั่นไม่ได้ช่วยอะไร บนเว็บไซต์ H2ฉันได้พบสิ่งต่อไปนี้ซึ่งอาจช่วยได้ในบางกรณี

โดยค่าเริ่มต้นการปิดการเชื่อมต่อล่าสุดไปยังฐานข้อมูลจะปิดฐานข้อมูล สำหรับฐานข้อมูลในหน่วยความจำหมายความว่าเนื้อหาหายไป หากต้องการให้ฐานข้อมูลเปิดอยู่ให้เพิ่ม; DB_CLOSE_DELAY = -1 ใน URL ฐานข้อมูล ในการเก็บเนื้อหาของฐานข้อมูลในหน่วยความจำตราบเท่าที่เครื่องเสมือนยังใช้งานอยู่ให้ใช้ jdbc: h2: mem: test; DB_CLOSE_DELAY = -1

อย่างไรก็ตามปัญหาของฉันคือเพียงแค่สคีมาที่ควรแตกต่างจากแบบเริ่มต้น ดังนั้นการใช้งาน

JDBC URL: jdbc:h2:mem:test

ฉันต้องใช้:

JDBC URL: jdbc:h2:mem:testdb

จากนั้นตารางสามารถมองเห็นได้


ขอบคุณ "testdb" เป็นอีกหนึ่งการแก้ไขสำหรับฉันด้วย (นอกเหนือจาก "DB_CLOSE_DELAY = -1")!
boly38

4

ฉันมีปัญหาเดียวกันและเปลี่ยนการกำหนดค่าของฉันใน application-test.properties เป็น:

#Test Properties
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop

และการพึ่งพาของฉัน:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.198</version>
        <scope>test</scope>
    </dependency>

และคำอธิบายประกอบที่ใช้กับคลาสทดสอบ:

@RunWith(SpringRunner.class)
@DataJpaTest
@ActiveProfiles("test")
public class CommentServicesIntegrationTests {
...
}

3

ฉันพยายามดึงข้อมูลเมตาของตาราง แต่มีข้อผิดพลาดดังต่อไปนี้:

โดยใช้:

String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";

DatabaseMetaData metaData = connection.getMetaData();
...
metaData.getColumns(...);

ส่งคืนชุดผลลัพธ์ ResultSet ที่ว่างเปล่า

แต่การใช้ URL ต่อไปนี้แทนจะทำงานได้อย่างถูกต้อง:

String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false";

ไม่จำเป็นต้องระบุ: DATABASE_TO_UPPER = false


นี้ไม่ได้เพิ่มอะไรไม่ได้ครอบคลุมโดยนี้คำตอบ จากการตรวจสอบ
Wai Ha Lee

3

เมื่อเปิด h2-console JDBC URL จะต้องตรงกับที่ระบุในคุณสมบัติ:

spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb

spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true

spring.h2.console.enabled=true

ป้อนคำอธิบายรูปภาพที่นี่

สิ่งใดที่ดูเหมือนชัดเจน แต่ฉันใช้เวลาหลายชั่วโมงในการหาข้อมูลนี้ ..


2

แก้ไขได้โดยการสร้างไฟล์ src / test / resources ใหม่ + ใส่ไฟล์ application.properties ระบุอย่างชัดเจนเพื่อสร้าง test dbase:

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create

1

ฉันมาที่โพสต์นี้เพราะฉันมีข้อผิดพลาดเดียวกัน

ในกรณีของฉันฐานข้อมูลไม่ได้ถูกดำเนินการดังนั้นตารางไม่ได้เลย

ปัญหาของฉันคือโครงสร้างโฟลเดอร์สำหรับสคริปต์วิวัฒนาการไม่ถูกต้อง

จาก: https://www.playframework.com/documentation/2.0/Evolutions

เล่นแทร็กวิวัฒนาการฐานข้อมูลของคุณโดยใช้สคริปต์วิวัฒนาการหลาย ๆ สคริปต์เหล่านี้เขียนด้วย SQL แบบเก่าธรรมดาและควรอยู่ในไดเร็กทอรี conf / evolutions / {database name} ของแอปพลิเคชันของคุณ หากการวิวัฒนาการนำไปใช้กับฐานข้อมูลเริ่มต้นของคุณพา ธ นี้คือ conf / evolutions / default

ฉันมีโฟลเดอร์ชื่อconf / evolutions.default ที่สร้างโดย eclipse ปัญหาหายไปหลังจากฉันแก้ไขโครงสร้างโฟลเดอร์เป็นconf / evolutions / default


0
<bean id="benchmarkDataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1" />
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>

0

มีปัญหาเดียวกันที่แน่นอนลองทั้งหมดข้างต้น แต่ไม่ประสบความสำเร็จ สาเหตุที่ค่อนข้างตลกของข้อผิดพลาดคือJVM เริ่มเร็วเกินไปก่อนที่จะสร้างตารางฐานข้อมูล (ใช้ไฟล์ data.sql ใน src.main.resources) ดังนั้นฉันจึงใส่ตัวจับเวลา Thread.sleep (1,000) เพื่อรอเพียงวินาทีก่อนที่จะโทร "select * from person" ทำงานอย่างไม่มีที่ติตอนนี้

application.properties:

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

data.sql:

create table person
(
id integer not null,
name varchar(255) not null,
location varchar(255),
birth_date timestamp,
primary key(id)
);

insert into person values (
10001, 'Tofu', 'home', sysdate()
);

PersonJdbcDAO.java:

    public List<Person> findAllPersons(){
    return jdbcTemplate.query("select * from person", 
        new BeanPropertyRowMapper<Person>(Person.class));
}

ชั้นหลัก:

Thread.sleep(1000);
logger.info("All users -> {}", dao.findAllPersons());

0

ฉันพบว่ามันทำงานหลังจากเพิ่มการพึ่งพาของSpring Data JPAใน Spring boot เวอร์ชั่น 2.2.6.RELEASE -

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

เพิ่มการกำหนดค่า H2 DB ใน application.yml -

spring:
  datasource:
    driverClassName: org.h2.Driver
    initialization-mode: always
    username: sa
    password: ''
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
  h2:
    console:
      enabled: true
      path: /h2
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: none

0

ฉันพบวิธีแก้ปัญหาโดยเพิ่มการกำหนดค่านี้:

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

การกำหนดค่าแบบเต็ม (ด้วย spring.datasource.url แบบง่าย):

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop

ฉันทำงานกับh2 รุ่น 1.4.200และSpring-Boot 2.2.6.RELEASE


-2

time.sleep (1000)

สิ่งนี้ใช้ได้สำหรับฉัน เพียงลองถ้าพีซีของคุณช้าคุณสามารถเพิ่มระยะเวลาของเธรดเพื่อให้ DB ทำงานได้ดีและ JVM สามารถรับตารางของเราได้

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