Grails 3 Oracle AssertionFailure on Save操作且未启用getGeneratedKeys支持

时间:2015-06-09 21:52:19

标签: oracle grails grails-3.0

问题:错误500:内部服务器错误

URI: /listing/save
Class: org.hibernate.AssertionFailure
Message: getGeneratedKeys() support is not enabled

配置

  • 环境:发展
  • 应用资料:网页
  • 应用版本:0.1
  • Grails版本:3.0.1
  • Groovy版本:2.4.3
  • JVM版本:1.8.0_45(64位)
  • 重新加载有效:true

可用的控制器:

  • phonebook.ListingController

操作系统:Windows 7 数据库:Oracle 11g R2企业版(11.2.0.4 64位)

调试输出包含:

Grails application running at http://localhost:8080
ERROR org.hibernate.AssertionFailure - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session):     org.hibernate.AssertionFailure: getGeneratedKeys() support is not enabled
ERROR org.grails.web.errors.GrailsExceptionResolver - AssertionFailure occurred when processing request: [POST] /listing/save - parameters:
name: Scott
phone: 555-1212
create: Create
getGeneratedKeys() support is not enabled. Stacktrace follows:
org.hibernate.AssertionFailure: getGeneratedKeys() support is not enabled
    at phonebook.ListingController.$tt__save(ListingController.groovy:38) ~[main/:na]
    at grails.transaction.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:93) ~[grails-core-3.0.1.jar:3.0.1]
    at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:90) ~[grails-core-3.0.1.jar:3.0.1]
    at grails.transaction.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:93) ~[grails-core-3.0.1.jar:3.0.1]
    at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:90) ~[grails-core-3.0.1.jar:3.0.1]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_45]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_45]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]

File: grails-app\controllers\phonebook\ListingController
Line: 38
Content:         listing.save flush:true

重现问题:

  • C:\开发> grails create-app phonebook
  • C:\开发> cd phonebook

编辑:build.gradle

dependencies {
  ...
  runtime "com.oracle:jdbc-lib-ojdbc6:11.2.0.4"
  ...
}

注意:Oracle客户端ojdbc6.jar在上面指定的坐标处添加到本地Maven存储库。

编辑:grails-app \ conf \ application.yml

...
dataSource:
    pooled: true
    jmxExport: true
    driverClassName: oracle.jdbc.OracleDriver
    username: scott
    password: tiger

environments:
    development:
        dataSource:
            dbCreate: update
            url: jdbc:oracle:thin:@localhost:1521/sbx1
...

C:\开发\电话簿> grails create-domain-class phonebook.listing 编辑:的grails-app \域\电话簿\ Listing.groovy

package phonebook

class Listing {
    String name
    String phone

    static constraints = {
        name maxSize: 50
        phone maxSize: 14
    }
}

C:\Dev\phonebook> grails generate-all phonebook.listing
C:\Dev\phonebook> grails run-app

以下确认应用程序已连接到数据库并成功创建表:

SQL> describe listing
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER(19)
 VERSION                                   NOT NULL NUMBER(19)
 NAME                                      NOT NULL VARCHAR2(50 CHAR)
 PHONE                                     NOT NULL VARCHAR2(14 CHAR)

模式中还创建了两个序列:

HIBERNATE_SEQUENCE
LISTING_SEQ

注意:这些必须是在我多次尝试修改域类中的映射属性以生成ID时创建的。

嵌入式Tomcat服务器在http://localhost:8080/上运行后的操作 Internet Explorer:http://localhost:8080/ 点击链接:可用控制器> phonebook.ListingController 点击:新列表 完成表单并单击:创建 结果:上面描述的Grails异常

研究和故障排除活动:

  • 问题不存在只是将Oracle改为H2 / HSQL文件/内存数据库
  • 发现hibernate.jdbc.use_get_generated_keys设置但通过在application.yml配置文件中设置true设置解决问题失败
  • 在grails-app / conf / DataSource.groovy中找到了对设置的多个引用,但这是使用application.yml的Grails 3
  • 在域类中尝试使用生成器
  • 映射ID列的多个属性
  • 在Grails 3文档中发现很少或根本没有涉及此主题的信息
  • Hibernate文档涵盖配置设置和ID生成器,但不提供该信息的Grails / Groovy应用程序
  • Hibernate文档声明未明确设置hibernate.jdbc.use_get_generated_keys会导致jdbc连接数据库元数据自动设置

我试图通过grails-app \ conf \ application.yml中的以下部分解决问题:

hibernate:
    jdbc:
        use_get_generated_keys: true
    cache:
        queries: false
...

我怀疑该解决方案涉及grails-app \ conf \ application.yml中的特定设置,但尚未发现配置设置的正确组合。

4 个答案:

答案 0 :(得分:0)

您也可以尝试从身份序列生成器(我相信Oracle方言的默认值)切换到seq-hilo:

在Grails 2.x中,您可以通过以下方式完成:

grails.gorm.default.mapping = {
    id generator: 'seqhilo', params: [max_lo: 1000]
}

我认为它在application.yml文件中的3.x中的工作方式类似。这应该可以防止hibernate甚至需要使用getGeneratedKeys()方法,因为它会将id从它自己的内存池中绑定到insert中,而不是在insert语句中执行seq.nextval。

答案 1 :(得分:0)

好的,当查看application.yml配置文件中的哪个位置放置第一个答案的建议时,我发现我使用的hibernate.jdbc.use_get_generated_keys = true设置实际上是在grails块下。虽然以前从未使用过yml文件,但我并不知道缩进和块形成配置设置的潜在重要性。当我第一次对文件进行编辑时,我查看是否已经有一个休眠部分,我将此设置放在该块中,从而导致设置为grails.hibernate.jdbc.use_get_generated_keys。我在hibernate的root(无缩进)下创建了设置并进行了测试。结果是成功完成了行动。

我希望这篇文章能够帮助其他新用户使用这个配置文件,这个文件在以groovy为中心的框架中似乎不合适。我将查看创建新的grails应用程序是否有一个选项来使用groovy配置文件而不是yml文件。

答案 2 :(得分:0)

通过添加

修复了Oracle 12的这个问题
   jdbc:
      use_get_generated_keys: true

并将oracle jdbc驱动程序升级到ojdbc7 12.1.0.2(12.1.0.1不起作用)

答案 3 :(得分:0)

对于Grails 3,Hibernte 4,Oracle 10c +以下配置可用。

在build.gradle中配置了Hibernate 4,默认情况下是Grails 3.1.6的

在application.yml

hibernate:
    jdbc:
        use_get_generated_keys: true
    id:
        new_generator_mappings: true

然后在域对象中配置id字段以使用Oracle序列作为密钥,如下所示:

class Person {

    String name

    static constraints = {
        id generator:'sequence-identity', params:[sequence:'person_key_seq']
    }
}

Oracle最近才推出自动生成的ID字段,我认为12.但Hibernate 4只有org.hibernate.dialect.Oracle10gDialect,所以你不能使用新的Oracle自动密钥功能而不使用Hibernate 5如果您可以使用Hibernate 5,那么Oracle12cDialect可用,这将允许Hibernate和Oracle在直接处理数据库时在GORM和SQL中为您生成密钥生成。但是,从Grails 3.1.6开始,在某些服务器上成功部署Hibernate 5存在问题,因此请注意,如果您尝试切换。