Category Archive: Hibernate

Транзакции в debug-режиме

Транзакции в Hibernate работают не всегда прозрачно.

Если для отладки запросов в Hibernate мы используем show-sql: true в application.yml, то для включения логирования транзации нужно переключить уровень логирования на DEBUG для определенного класса.

Следующая настройка для Hibernate 5 и системы логирования SLF4J.

В файл logback-spring.xml (или logback.xml) добавьте следующую строку:


После рестарта приложения в логах должны появится следующие строки:

1) Начало транзакции

...TransactionImpl         : begin

2) Коммит транзакции

...TransactionImpl         : committing

3) Откат транзакции

...TransactionImpl         : rolling back

Hibernate Envers проблема с размером приращения последовательности

В проект трехлетней давности не получилось прикрутить Hibernate Envers, возникала ошибка при запуске приложения:

Caused by: org.hibernate.MappingException: 
The increment size of the [hibernate_sequence] sequence is set to [1] 
in the entity mapping while the associated database sequence increment size is [50].

На том проекте Envers не сильно нужен был, поэтому обошлись без него.

На новом проекте все-таки возникла острая необходимость в использовании Envers, пришлось потратить время, чтобы решить данную проблему.

В нашем проект используется не hibernate_sequence, а sequence_generator, но принцип тот же.

Проблема в том, что в базе данных у sequence шаг приращения 50 (в целях производительности), а в коде у какой-то сущности с данным sequence приращение равно 1. Эта сущность - revinfo.

Нужно переопределить RevInfo, добавив следующую сущность в ваш проект:

@Entity
@Table(name = "revinfo")
@RevisionEntity
public class CustomRevisionEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    @RevisionNumber
    private long rev;

    @RevisionTimestamp
    private long timestamp;

    public long getRev() {
        return rev;
    }

    public void setRev(long rev) {
        this.rev = rev;
    }

    public long getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(long timestamp) {
        this.timestamp = timestamp;
    }
}

Ключевое изменение - это строки:

 @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
 @SequenceGenerator(name = "sequenceGenerator")

Которые явно задают sequence, который будет использовать таблица revinfo. В нашем случае - это sequence_generator.

Если помогло, отпишитесь в комментах. 🙂

p.s. Дефолтная revinfo какая-то косячная.

Идентификатор ревизии почему-то integer, а не long.

Также не читабельна ревизия в виде long timestamp, но есть две альтернативы. Либо только дата, либо только время. Что еще неудобнее, а хотелось бы человекочитаемую дату со временем.

Совет: лучше переопределить revinfo, даже если у вас нет проблем с последовательностями.