Spring boot、JPA、Hibernate 和 H2 DB 测试 - 序列不起作用 - 意外的代码路径”;SQL 语句:调用 seq_my_jobs [50000-193] 的下一个值

Posted

技术标签:

【中文标题】Spring boot、JPA、Hibernate 和 H2 DB 测试 - 序列不起作用 - 意外的代码路径”;SQL 语句:调用 seq_my_jobs [50000-193] 的下一个值【英文标题】:Spring boot, JPA, Hibernate and H2 DB tests - Sequence not working - Unexpected code path"; SQL statement: call next value for seq_my_jobs [50000-193] 【发布时间】:2017-06-28 20:37:03 【问题描述】:

我的 Spring Boot 应用上有一个实体:

@Entity
@Table(name = "MY_JOBS")
public class InstallationJobEntity 

    @GeneratedValue(generator="SEQUENCE_GENERATOR", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name="SEQUENCE_GENERATOR",sequenceName="SEQ_MY_JOBS", allocationSize=100)
    @Id
    @Column(name = "ID")
    private Long id;

    @Column(name = "CONFIGURATION_DATA")
    @Lob
    private String configurationData;

    public Long getId() 
        return id;
    

    public String getConfigurationData() 
        return configurationData;
    

    public void setId(Long id) 
        this.id = id;
    

    public void setConfigurationData(String configurationData) 
        this.configurationData = configurationData;
    

对于我的测试,我在 application.yml 上配置 H2 DB:

spring:
    jpa:
        database: H2
        show-sql: true
        hibernate:
            ddl-auto: none
    properties:
        hibernate:
            dialect: common.H2Dialect
    datasource:
        initialize: true
        schema: schema.sql
        data: data.sql
        url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;Mode=Oracle;DATABASE_TO_UPPER=false;
        username:
        platform: h2
        driver-class-name: org.h2.Driver
        testWhileIdle: true
        validationQuery: SELECT 1 from DUAL

在 schema.sql 上,我创建了表和序列(我直接使用 JdbcTemplate 对其进行了测试,它正在工作)

在运行我的测试时,我得到了这个异常:

2017-02-10 15:07:47.764 ERROR 22618 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : General error: "java.lang.RuntimeException: Unexpected code path"; SQL statement:
call next value for seq_my_jobs [50000-193]

org.springframework.orm.jpa.JpaSystemException: could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:491)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
    at com.sun.proxy.$Proxy121.save(Unknown Source)
    at softwaremanagement.services.dao.DAOServiceImpl.createInstallationJob(DAOServiceImpl.java:65)
    at softwaremanagement.services.BLServiceImpl.installationRequest(BLServiceImpl.java:51)
    at softwaremanagement.orchestration.actors.BLIntegrationTest.integrationWithMockGWFromBLServiceLevel(BLIntegrationTest.java:88)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: org.hibernate.exception.GenericJDBCException: could not extract ResultSet
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79)
    at org.hibernate.id.SequenceGenerator.generateHolder(SequenceGenerator.java:116)
    at org.hibernate.id.SequenceHiLoGenerator$1.getNextValue(SequenceHiLoGenerator.java:71)
    at org.hibernate.id.enhanced.LegacyHiLoAlgorithmOptimizer.generate(LegacyHiLoAlgorithmOptimizer.java:60)
    at org.hibernate.id.SequenceHiLoGenerator.generate(SequenceHiLoGenerator.java:67)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101)
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
    at com.sun.proxy.$Proxy116.persist(Unknown Source)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:506)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:503)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:488)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    ... 42 more
Caused by: org.h2.jdbc.JdbcSQLException: General error: "java.lang.RuntimeException: Unexpected code path"; SQL statement:
call next value for seq_my_jobs [50000-193]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
    at org.h2.message.DbException.get(DbException.java:168)
    at org.h2.message.DbException.convert(DbException.java:295)
    at org.h2.command.Command.executeQuery(Command.java:213)
    at org.h2.jdbc.JdbcPreparedStatement.executeQuery(JdbcPreparedStatement.java:110)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
    ... 77 more
Caused by: java.lang.RuntimeException: Unexpected code path
    at org.h2.message.DbException.throwInternalError(DbException.java:242)
    at org.h2.message.DbException.throwInternalError(DbException.java:255)
    at org.h2.engine.Session.addLock(Session.java:842)
    at org.h2.mvstore.db.MVTable.doLock2(MVTable.java:254)
    at org.h2.mvstore.db.MVTable.doLock1(MVTable.java:202)
    at org.h2.mvstore.db.MVTable.lock(MVTable.java:167)
    at org.h2.engine.Database.lockMeta(Database.java:909)
    at org.h2.engine.Database.removeSchemaObject(Database.java:1842)
    at org.h2.table.Table.removeChildrenAndResources(Table.java:530)
    at org.h2.table.TableView.removeChildrenAndResources(TableView.java:414)
    at org.h2.engine.Session.cleanTempTables(Session.java:948)
    at org.h2.engine.Session.commit(Session.java:643)
    at org.h2.schema.Sequence.flush(Sequence.java:302)
    at org.h2.schema.Sequence.getNext(Sequence.java:269)
    at org.h2.expression.SequenceValue.getValue(SequenceValue.java:30)
    at org.h2.command.dml.Call.query(Call.java:65)
    at org.h2.command.CommandContainer.query(CommandContainer.java:110)
    at org.h2.command.Command.executeQuery(Command.java:201)
    ... 79 more

主要问题是: 原因:org.h2.jdbc.JdbcSQLException: 一般错误:“java.lang.RuntimeException: Unexpected code path”; SQL 语句: 调用 seq_my_jobs [50000-193] 的下一个值

我还尝试使用(所有注释的代码都不能正常工作......)实现我自己的 H2 方言:

public class H2Dialect extends org.hibernate.dialect.H2Dialect 
@Override
public String getSequenceNextValString(String sequenceName) 
//        return "SELECT "+ sequenceName + ".nextval";
//        return "SELECT "+sequenceName+".nextval from DUAL";
//        return "SELECT "+"NEXTVAL('"+sequenceName+"')";
        return "SELECT SEQ_MY_JOBS.nextVal from DUAL";
    

有什么想法吗?

【问题讨论】:

【参考方案1】:

由于您在 Oracle 兼容模式 Mode=Oracle 下运行 H2,因此请使用 oracle 方言:

 properties:
        hibernate:
            dialect: org.hibernate.dialect.Oracle10gDialect 

【讨论】:

刚刚试了一下——我也遇到了同样的异常: 原因:org.h2.jdbc.JdbcSQLException:一般错误:“java.lang.RuntimeException:意外的代码路径”; SQL语句:select seq_my_jobs.nextval from dual [50000-193] 我赌的是区分大小写的匹配。请删除DATABASE_TO_UPPER=false 并重试。 H2 文档说将其设置为 false 是实验性的。 已经试过了 - 出现同样的异常。我觉得这与 H2 何时创建序列或何时允许开始使用它有关。尝试运行查询时: select seq_my_jobs.nextval from dual with jdbcTemplate.queryForRowSet 它不起作用,直到我使用 jdbcTemplate.queryForInt 运行它,它返回一个结果。之后 - 它也与 jdbcTemplate.queryForRowSet 一起使用

以上是关于Spring boot、JPA、Hibernate 和 H2 DB 测试 - 序列不起作用 - 意外的代码路径”;SQL 语句:调用 seq_my_jobs [50000-193] 的下一个值的主要内容,如果未能解决你的问题,请参考以下文章

制作多个 EntityManager(Spring-Boot-JPA、Hibernate、MSSQL)

Spring Boot / JPA / Hibernate,如何根据 Spring 配置文件切换数据库供应商?

Spring boot之 JPA/Hibernate/Spring Data

Spring Boot JPA Hibernate - 以毫秒精度存储日期

当加载 spring-boot 和 spring-data-jpa 时,Hibernate 无法加载 JPA 2.1 Converter

Spring Boot 2.1 缺少多个 org.hibernate.jpa.event 类