Пользовательские методы вставки и обновления побеждены автоматическим сохранением

Я портирую приложение Grails из Oracle в базу данных MySQL. Первоначальная версия Oracle является устаревшей базой данных, которая использует несколько сложных представлений, использующих функцию Oracle INSTEAD OF INSERT OR UPDATE, которой нет в MySQL. В качестве обходного пути я реализовал методы вставки и обновления в классах домена, которые указывают на эти виды представлений. Например,

class AdminUser {
    //...
    def update() {
        if(this.validate()) {
            Sql sql = Utils.getHibernateSql()

            sql.execute(
                "update table_x ...",
                [...]
            )

            sql.execute(
                "update table_y ...)",
                [...]
            )

            sql.execute(
                "update table_z ...",
                [...]
            )

            return true
        }

        return false
    }
    //...
}

Вот описание проблемы, с которой я сталкиваюсь в данный момент:

  1. В методе службы я загружаю экземпляр AdminUser, используя AdminUser.get
  2. Я изменяю загруженный экземпляр и вызываю update(), все выглядит хорошо
  3. Как только метод службы завершает выполнение, возникает исключение из-за чего-то, вызывающего save в экземпляре.

Как я могу предотвратить магическое сохранение, происходящее на шаге (3) (недавно я где-то читал, что Grails автоматически сохранит измененный экземпляр класса Domain, который еще не был сохранен при выходе из метода службы, но я не могу найти ссылка на этот ресурс прямо сейчас)?

2 ответа

Решение

Вы оставляете измененный экземпляр в сеансе гибернации с грязными полями. Когда сеанс гибернации сбрасывается, он пытается снова сохранить объект с обычным save() метод.

Одним из решений было бы отказаться от вашего объекта из спящего режима после того, как вы вручную сохранили изменения. Например:

def update() {
    if(this.validate()) {
        Sql sql = Utils.getHibernateSql()

        sql.execute(
            "update table_z ...",
            [...]
        )

        ...

        this.discard()  // remove the object from the hibernate session
        return true
    }

Кроме того, вы можете добавить это в ваш Config.groovy, чтобы потребовать явного сохранения объектов:

hibernate.flush.mode="manual"

Если вы используете read () вместо get(), то объект не будет автоматически сохранять изменения. Вы все еще можете вызывать save() явно, но стандартное поведение, при котором перехватчик OpenSessionInView сбрасывает все несохраненные грязные экземпляры, пропускает экземпляры, загруженные с помощью read().

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