You are here
Creating Tables for Hibernate Envers with Liquibase
Recently, I wanted to keep the change history of entities saved via Hibernate and also have a versioned database. Hence, I used Hibernate Envers and Liquibase.
The tables for envers, both the revinfo table and the _AUD tables for each entity, have to be included in the changeset of Liquibase:
<?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> <property name="long_type" value="bigint" dbms="postgresql"/> <property name="long_type" value="long" dbms="h2"/> <changeSet id="CreateBasicSchema" author="Steven Schwenke"> <createSequence sequenceName="hibernate_sequence" startValue="0" incrementBy="1"/> <createTable tableName="revinfo"> <column name="rev" type="integer" autoIncrement="true"> <constraints primaryKey="true"/> </column> <column name="revtstmp" type="bigint"/> </createTable> <createTable tableName="stuff"> <column name="id" type="${long_type}"> <constraints nullable="false" unique="true" primaryKey="true"/> </column> <column name="text" type="varchar(36)"> <constraints nullable="false"/> </column> </createTable> <createTable tableName="stuff_aud"> <column name="id" type="${long_type}"> <constraints nullable="false" /> </column> <column name="rev" type="integer"> <constraints referencedTableName="revinfo" foreignKeyName="fk_brands_stuff_revinfo" referencedColumnNames="rev" nullable="false"/> </column> <column name="revtype" type="integer"> <constraints nullable="false"/> </column> <column name="stuff" type="varchar(36)"> <constraints nullable="true"/> </column> </createTable> <addPrimaryKey tableName="stuff_aud" columnNames="id, rev" /> </changeSet> </databaseChangeLog>
The autoIncrement="true" in the revinfo table is quite important. Without it, new revisions don't have an ID and this exception occurs:
o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23502, SQLState: 23502 o.h.engine.jdbc.spi.SqlExceptionHelper : NULL nicht zulässig für Feld "REV" NULL not allowed for column "REV"; SQL statement: /* insert org.hibernate.envers.DefaultRevisionEntity */ insert into revinfo (rev, revtstmp) values (null, ?) [23502-200] org.springframework.dao.DataIntegrityViolationException: could not execute statement ...
The best way to prevent this exception from happening is the mentionend autoIncrement. However, it's also possible to create an entity for the revision:
import org.hibernate.envers.RevisionEntity; import org.hibernate.envers.RevisionNumber; import org.hibernate.envers.RevisionTimestamp; import javax.persistence.*; @RevisionEntity @Table(name = "revinfo") public class Revision { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @Column(nullable = false, name = "REV") @RevisionNumber private long rev; @Column(name = "revtstmp") @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; } }