Синтаксис DB2 (ограничение и грязное чтение) при работе H2 (в режиме DB2)

У меня есть несколько методов, которые я сейчас пытаюсь провести модульные тесты. Эти методы отлично работают (в производстве) на DB2 v8 с использованием Spring JdbcTemplates.

Каждый SQL допускает "грязное чтение", добавляя "WITH UR" в оператор. Кроме того, некоторые из них используют "предел", добавив, например, "ТОЛЬКО ВПЕРВЫЕ 1 ПЕРВАЯ СТРОКА".

Это отлично работает с реальной DB2, но я хочу провести модульное тестирование этих методов с базой данных в памяти - это где H2 входит.

Все работает нормально, если я удаляю "WITH UR" и "FETCH FIRST..", но я не хочу менять методы, а просто изменяю базу данных бэкэнда.

Насколько я понимаю, это невозможно напрямую с помощью H2, так как синтаксис другой (хотя я использую MODE=DB2).

Что теперь делать? Должен ли я использовать другую базу данных в памяти? Я не хочу ни менять методы, ни добавлять "тестовые" функции / хаки, так что это не нужно.

Идеи, а также высоко ценится!

РЕДАКТИРОВАТЬ

Я не уверен, что это я или что, но я получаю следующую ошибку. Обратите внимание, я использую Spring 3.1 и H2 1.3.166, а URL для базы данных: "jdbc:h2:~/testdb;MODE=DB2". Я понятия не имею, почему он не работает, потому что SQL работает при запуске в консоли H2, но не из моего модульного теста (думаю, это не H2, который сломан):

Tests run: 3, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.109 sec <<< FAILURE!
getAdvisor(impl.AdvisorServiceDaoImplTest)  Time elapsed: 0.078 sec  <<< ERROR!
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT * FROM ADVISOR FETCH FIRST 1 ROWS ONLY ]; nested exception is org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "SELECT * FROM ADVISOR FETCH[*] FIRST 1 ROWS ONLY "; SQL statement:
SELECT * FROM ADVISOR FETCH FIRST 1 ROWS ONLY  [42000-166]
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:233)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:603)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:662)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:702)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:178)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:185)
    at impl.AdvisorServiceDaoImpl.getAdvisor(AdvisorServiceDaoImpl.java:150)
    at impl.AdvisorServiceDaoImplTest.getAdvisor(AdvisorServiceDaoImplTest.java:69)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
    at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
    at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "SELECT * FROM ADVISOR FETCH[*] FIRST 1 ROWS ONLY "; SQL statement:
SELECT * FROM ADVISOR FETCH FIRST 1 ROWS ONLY  [42000-166]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:169)
    at org.h2.message.DbException.get(DbException.java:146)
    at org.h2.message.DbException.getSyntaxError(DbException.java:181)
    at org.h2.command.Parser.getSyntaxError(Parser.java:484)
    at org.h2.command.Parser.prepareCommand(Parser.java:233)
    at org.h2.engine.Session.prepareLocal(Session.java:415)
    at org.h2.engine.Session.prepareCommand(Session.java:364)
    at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1111)
    at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:71)
    at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:266)
    at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:245)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:581)
    ... 40 more

РЕДАКТИРОВАТЬ #2 В случае, если у кого-то есть такая же проблема, вот что я узнал Я использовал следующее:

<jdbc:embedded-database id="dataSource" type="H2">
    <jdbc:script location="classpath:sql/create_schemas.sql"/>
    <jdbc:script location="classpath:sql/create_tables.sql"/>
    <jdbc:script location="classpath:sql/create_test_data.sql"/>
</jdbc:embedded-database>

Это означает, что Spring повторно создаст экземпляр источника данных с помощью общего компонента, поэтому мои настройки были потеряны. Решение (в моем случае) состояло в том, чтобы просто загрузить базу данных программно с помощью следующего:

EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder.setName("salgdb").setType(EmbeddedDatabaseType.H2)
            .addScript("sql/create_schemas.sql")
            .addScript("sql/create_tables.sql")
            .addScript("sql/create_test_data.sql")
                .build();

2 ответа

Что вы можете сделать, это предоставить патч для базы данных H2, чтобы поддержать функцию "WITH UR":-)

"FETCH FIRST 1 ROWS ONLY" уже работает с последней версией H2, но только в режиме DB2. Чтобы включить режим DB2, добавьте ;MODE=DB2 на URL базы данных, как в:

jdbc:h2:~/data/test;mode=db2

Пример:

create table customer(id int);
select * from customer fetch first 1 rows only;

Я проверил это с H2 версии 1.3.166, но он также должен работать в более старых версиях, скорее всего 1.3.161 и новее. Чтобы проверить это вне Spring:

  • Скачать H2 с http://h2database.com/
  • Запустите инструмент консоли H2
  • Используйте URL базы данных: jdbc:h2:~/temp/testdb;MODE=DB2
  • Запустите операторы:

    create table ADVISOR(id int);

    SELECT * FROM ADVISOR FETCH FIRST 1 ROWS ONLY;

Я не получу исключения, если я сделаю это.

Начиная с версии 1.3.175 H2 также должен поддерживать "WITH UR". Журнал изменений H2

Другие вопросы по тегам