H2 इन-मेमोरी डेटाबेस। टेबल नहीं मिली


182

मुझे URL के साथ H2 डेटाबेस मिला है "jdbc:h2:test"। मैं उपयोग करके एक तालिका बनाता हूं 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 डिस्क पर आपके द्वारा बनाए गए डेटाबेस के बारे में पहले से कुछ नहीं जानता है।
बेंजामिन मस्को

कार्यक्रम का बाकी हिस्सा नहीं बदला - मैंने फिर से तालिका बनाई।
Jorn

जवाबों:


330

DB_CLOSE_DELAY=-1

hbm2ddl तालिका बनाने के बाद कनेक्शन को बंद कर देता है, इसलिए h2 इसे छोड़ देता है।

यदि आपके पास आपका कनेक्शन-यूआरएल इस तरह कॉन्फ़िगर किया गया है

jdbc:h2:mem:test

अंतिम कनेक्शन बंद होने पर डेटाबेस की सामग्री खो जाती है।

यदि आप अपनी सामग्री रखना चाहते हैं तो आपको यूआरएल को इस तरह कॉन्फ़िगर करना होगा

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काम नहीं करता है।
पीटर बेकर

हम मेमोरी के बजाय फ़ाइल में डेटा कैसे स्टोर कर सकते हैं?
सुलेमान खान

8
अगर आप किसी कोड में अपनी टेबल के नामकरण के लिए निचले मामले का उपयोग करते हैं, तो आपको पता होना चाहिए कि डिफ़ॉल्ट रूप से H2 अपरकेस सब कुछ का उपयोग करता है DATABASE_TO_UPPER = झूठ से बचने के लिए जैसे jdbc: h2: mem: test; DBCLCLE_DELAY = -1; DATABASE_TO_UPPER = false;
ऑलेक्ज़ेंडर पेट्रेनको

@ ऑलेक्ज़ेंडरपेट्रेंको - कि अनुगामी ';' समस्याओं का कारण लगता है। मुझे लगता है कि आपको इसे छोड़ने की आवश्यकता है।
वोल्क्समैन

102

मुझे पता है कि यह आपका मामला नहीं था, लेकिन मुझे भी यही समस्या थी क्योंकि H2 UPPERCASE नामों के साथ तालिकाओं का निर्माण कर रहा था, फिर केस-संवेदी व्यवहार कर रहा था, भले ही सभी लिपियों में (सृजन वाले सहित) मैं लोअरकेस का उपयोग करता था।

;DATABASE_TO_UPPER=falseकनेक्शन URL में जोड़कर हल किया गया ।


7
वाह - मुझे बहुत खुशी है कि आपने इसे साझा किया है! ऐसा कभी नहीं सोचा होगा।
एमएस-टीजी

1
उस प्रश्न का हल नहीं, जो उसी प्रश्न के साथ खोज करने पर मुझे होने वाली समस्या का समाधान था!
यायते

क्या यह DATABASE_TO_UPPER=falseबात एक init स्क्रिप्ट में SQL स्टेटमेंट के रूप में सेट करना संभव है ? (इसी तरह एक बयान के रूप में SET MODE PostgreSQL;) यदि हां, तो सटीक वाक्यविन्यास क्या है?
जोनिक

3
मैं इसे कई बार कैसे बढ़ा सकता हूं? आपका बहुत बहुत धन्यवाद! यह पहले उत्तर का हिस्सा होना चाहिए।
रिब्सग

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
जोर्न

1
मुझे लगता है कि मुझे परेशानी पता चल गया है। जब मैं कनेक्शन को बंद कर देता हूं तो तालिका के साथ बनाया गया था, फिर एक नया खोलें, डीबी चला गया है। जब मैं पिछले एक को बंद करने से पहले एक नया कनेक्शन खोलता हूं, तो डेटा बना रहता है। जब मैं किसी फ़ाइल का उपयोग करता हूं, तो डेटा (जाहिर है) हमेशा बना रहता है।
जोनर

7

H2 इन-मेमोरी डेटाबेस JVM के अंदर मेमोरी में डेटा स्टोर करता है। जब JVM बाहर निकलता है, तो यह डेटा खो जाता है।

मुझे संदेह है कि आप जो कर रहे हैं वह नीचे दिए गए दो जावा वर्गों के समान है। इनमें से एक वर्ग एक तालिका बनाता है और दूसरा इसमें सम्मिलित करने का प्रयास करता है:

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 \ Luc \ सामान> जावा CreateTable

C: \ Users \ Luc \ सामान> java InsertIntoTable
थ्रेड में अपवाद "मुख्य" org.h2.jdbc.JdbcSQLException: तालिका "PERSON" नहीं मिली; SQL कथन:
INSERT INTO PERSON (ID, FIRSTNAME, LASTNAME) VALUES (1, 'जॉन', 'डो') [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दिखाई दी थी। यह वह जगह थी जहां एच 2 ने तालिका रखी थी, और चूंकि यह डिस्क पर संग्रहीत किया गया था, तालिका अभी भी सम्मिलित करने योग्य वर्ग को खोजने के लिए वहां थी।


1
कृपया ध्यान दें कि registerDriver()कॉल अनावश्यक है: सबसे पहले: एक साधारण Class.forName () अधिकांश JDBC ड्राइवरों के लिए एक ही करता है और (अधिक महत्वपूर्ण बात) यह जावा 6 und के लिए पूरी तरह से अनावश्यक है, जो ऑटो-डिटेक्ट (संगत) JDBC ड्राइवरों पर classpath।
जोआचिम सॉउर

स्मृति db में केवल तब तक मौजूद रहता है जब तक कि स्मृति का स्वामित्व वाला प्रोग्राम चल रहा हो? वाह, मुझे कोई पता नहीं था> _ <लेकिन वास्तव में, मुझे पता है कि मैं क्या करने की कोशिश कर रहा हूं। आपके उत्तर को पढ़कर, मुझे यकीन नहीं है कि आप करते हैं।
२२:११

2
@ जोर्न: मैं नहीं जान सकता कि आप क्या करने की कोशिश कर रहे हैं, मैं आपके द्वारा दी गई जानकारी के आधार पर अनुमान लगा रहा हूं। आपकी समस्या को प्रदर्शित करते हुए SSCCE ( sscce.org ) प्रदान करने के लिए यह अधिक उपयोगी हो सकता है - मैं आपके प्रश्न को उस संबंध में 'पूर्ण' नहीं कहूंगा। मैंने उपरोक्त उत्तर प्रदान किया क्योंकि एसओ (प्रोग्रामिंग के लिए नए लोग, मुख्य रूप से) पर लोग हैं जो सोच सकते हैं कि 'इन-मेमोरी' डेटाबेस डेटा को कंप्यूटर की मेमोरी में कहीं संग्रहीत करता है जहां यह प्रोग्राम इनवोकेशन के बीच जीवित रह सकता है। आपका प्रश्न मुझे समझाने के लिए पर्याप्त नहीं था कि आप इन लोगों में से एक नहीं थे।
ल्यूक वुडवर्ड

5

मैंने जोड़ने की कोशिश की है

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

हालाँकि, इससे कोई मदद नहीं मिली। पर एच 2 साइट , मैं निम्नलिखित है, जो वास्तव में कुछ मामलों में मदद कर सकता है मिल गया है।

डिफ़ॉल्ट रूप से, डेटाबेस से अंतिम कनेक्शन बंद करने से डेटाबेस बंद हो जाता है। इन-मेमोरी डेटाबेस के लिए, इसका मतलब है कि सामग्री खो गई है। डेटाबेस को खुला रखने के लिए, डेटाबेस URL में DB_CLOSE_DELAY = -1 जोड़ें। जब तक वर्चुअल मशीन जीवित है, तब तक इन-मेमोरी डेटाबेस की सामग्री को रखने के लिए 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

मेरे पास एक ही समस्या थी और इसने मेरे विन्यास को अनुप्रयोग-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(...);

एक खाली परिणाम लौटाया।

लेकिन इसके बजाय निम्नलिखित URL का उपयोग करना ठीक से काम किया:

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

निर्दिष्ट करने की आवश्यकता थी: DATABASE_TO_UPPER = false


यह इस उत्तर द्वारा कवर नहीं की गई कुछ भी नहीं जोड़ता है । समीक्षा से
वाई हा ली

3

H2- कंसोल खोलते समय, 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 / परीक्षण / संसाधन फ़ोल्डर + इंसर्ट Application.properties फ़ाइल बनाकर, स्पष्ट रूप से परीक्षण dbase बनाने के लिए निर्दिष्ट करके:

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

1

मैं इस पोस्ट पर आया क्योंकि मेरी वही त्रुटि थी।

मेरे मामले में डेटाबेस के प्रस्तावों को निष्पादित नहीं किया गया था, इसलिए तालिका बिल्कुल भी नहीं थी।

मेरी समस्या यह थी कि विकास लिपियों के लिए फ़ोल्डर की संरचना गलत थी।

से: https://www.playframework.com/documentation/2.0/Evolutions

कई एक्सपोज़र स्क्रिप्ट का उपयोग करके अपने डेटाबेस के विकास को ट्रैक करें। ये स्क्रिप्ट सादे पुरानी एसक्यूएल में लिखी गई हैं और आपके आवेदन की निर्देशिका / evolutions / {डेटाबेस नाम} निर्देशिका में स्थित होनी चाहिए। यदि आपके डिफ़ॉल्ट डेटाबेस पर एवोल्यूशन लागू होता है, तो यह पथ गोपनीय / एवोल्यूशन / डिफ़ॉल्ट है।

मेरे पास एक फ़ोल्डर था जिसे ग्रहण द्वारा निर्मित conf / evolutions.default कहा जाता था । समस्या को गायब करने के बाद मैं फ़ोल्डर संरचना को सही करने के लिए / evolutions / डिफ़ॉल्ट


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

सटीक एक ही मुद्दा था, उपरोक्त सभी की कोशिश की, लेकिन सफलता के बिना। त्रुटि के बजाय मज़ेदार कारण यह था कि डीबी टेबल बनने से पहले जेवीएम बहुत तेज़ हो गया था, (src.main.resources में data.sql फ़ाइल का उपयोग करके)। इसलिए मैंने "व्यक्ति से चयन करें" कॉल करने से पहले सिर्फ एक सेकंड इंतजार करने के लिए एक थ्रेड। स्लीप (1000) टाइमर लगा दिया है। अब निर्दोष रूप से काम कर रहा है।

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

मैंने पाया कि स्प्रिंग बूट संस्करण 2.2.6.RASEASE पर स्प्रिंग डेटा JPA की निर्भरता को जोड़ने के बाद यह काम कर रहा है -

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

Application.yml में H2 DB कॉन्फ़िगरेशन जोड़ें -

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

पूर्ण विन्यास (सरल बसंत के साथ .atasource.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 और स्प्रिंग-बूट 2.2.6 के साथ काम कर रहा हूं। कृपया


-2

Time.sleep (1000);

यह मेरे लिए काम है। बस कोशिश करने के लिए, यदि आपका पीसी धीमा है, तो आप थ्रेड की समय अवधि बढ़ा सकते हैं ताकि DB ठीक काम करे और JVM को हमारी तालिका मिल सके।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.