Grails 3 Oracle AssertionFailure при сохранении с отключенной поддержкой getGeneratedKeys

Проблема: Ошибка 500: Внутренняя ошибка сервера

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

Конфигурация

  • Окружающая среда: разработка
  • Профиль приложения: веб
  • Версия приложения: 0.1
  • Версия Grails: 3.0.1
  • Крутая версия: 2.4.3
  • Версия JVM: 1.8.0_45 (64-разрядная версия)
  • Перезагрузка активна: правда

Доступные контроллеры:

  • phonebook.ListingController

Операционная система: Windows 7 База данных: Oracle 11g R2 Enterprise Edition (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:\Dev> телефонная книга Grails Create-App
  • C:\Dev> cd телефонная книга

Изменить: build.gradle

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

Примечание. Клиент Oracle ojdbc6.jar добавлен в локальный репозиторий Maven по указанным выше координатам.

Изменить: приложение grails\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:\Dev\phonebook> grails create-domain-class phonebook.listing Edit:grails-app\domain\phonebook\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

Примечание. Должно быть, они были созданы в результате моих многочисленных попыток изменить атрибуты сопоставления в классе домена для генерации идентификатора.

Действие после запуска встроенного сервера Tomcat в http://localhost:8080/ Internet Explorer: http://localhost:8080/ Нажмите на ссылку: Доступные контроллеры > phonebook.ListingController Нажмите: Новый список Заполните форму и нажмите: Создать Результат: Исключение Grails описано выше

Исследования и действия по устранению неполадок:

  • Проблема отсутствует, это только изменение Oracle на файл H2/HSQL/базу памяти
  • Обнаружена настройка hibernate.jdbc.use_get_generated_keys, но не удалось решить проблему, поместив настройку true в файл конфигурации application.yml.
  • Найдено несколько ссылок на настройки в файле grails-app/conf/DataSource.groovy, но это Grails 3, в котором используется application.yml.
  • Попытка нескольких атрибутов в классе домена для сопоставления столбца идентификатора с использованием генераторов
  • В документации по Grails 3 почти нет информации по этой теме.
  • Документация Hibernate охватывает параметры конфигурации и генераторы идентификаторов, но не обеспечивает применение этой информации в 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, но не обнаружил правильной комбинации параметров конфигурации.


person TeamDitto    schedule 09.06.2015    source источник


Ответы (4)


Хорошо, когда я искал, где в файле конфигурации application.yml разместить предложение из первого представленного ответа, я обнаружил, что параметр hibernate.jdbc.use_get_generated_keys = true, который я использовал, фактически находился в блоке Grails. Никогда ранее не работавший с yml-файлами, я не знал о потенциальной важности того, как отступы и блоки формируют параметры конфигурации. Когда я впервые внес изменения в файл, я посмотрел, есть ли уже раздел гибернации, я поместил этот параметр в этот блок, в результате чего получился параметр grails.hibernate.jdbc.use_get_generated_keys. Я создал настройку под корнем (без отступа) для спящего режима и протестировал. Результатом стало успешное завершение акции.

Я надеюсь, что этот пост поможет другим новым пользователям в работе с этим файлом конфигурации, который кажется неуместным в среде, основанной на groovy. Я посмотрю, есть ли возможность при создании нового приложения Grails использовать файл конфигурации groovy вместо файла yml.

person TeamDitto    schedule 10.06.2015
comment
В grails3 работает use_get_generated_keys в application.yml, в корне, как вы упомянули. - person Stefano Scarpanti; 18.08.2019

Вы также можете попробовать переключиться с генератора идентификационных последовательностей (я полагаю, что он используется по умолчанию для диалекта Oracle) на seq-hilo:

В Grails 2.x это делается с помощью:

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

Я предполагаю, что это будет работать аналогично в 3.x в файле application.yml. Это должно помешать спящему режиму даже использовать метод getGeneratedKeys(), поскольку он привязывает идентификатор к вставке из собственного пула в памяти вместо выполнения seq.nextval в операторе вставки.

person Aaron    schedule 09.06.2015

Если бы эта проблема с Oracle 12 была исправлена ​​путем добавления

   jdbc:
      use_get_generated_keys: true

и обновление драйвера oracle jdbc до ojdbc7 12.1.0.2 (12.1.0.1 не работает)

person ron riley    schedule 26.01.2016

Для Grails 3, Hibernte 4, Oracle 10c+ работает следующая конфигурация.

Hibernate 4 настроен в build.gradle, который по умолчанию используется в Grails 3.1.6

В приложении.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 только недавно выпустил автоматически сгенерированные поля идентификатора, я думаю, 12. Но Hibernate 4 имеет только org.hibernate.dialect.Oracle10gDialect, поэтому вы не можете использовать новую функцию автоматического ключа Oracle без Hibernate 5. Если вы можете использовать Hibernate 5, а затем доступен Oracle12cDialect, который позволит Hibernate и Oracle просто позаботиться о генерации ключей для вас, как в GORM, так и в SQL при непосредственной работе с базой данных. Однако, начиная с Grails 3.1.6, возникают проблемы с успешным развертыванием Hibernate 5 на некоторых серверах, поэтому будьте осторожны при попытке переключения.

person DAC    schedule 06.05.2016