Use envers to Record Data Changes

  hibernate

Order

Hibernate’s envers module provides a set of mechanisms to record changes in data. Here is a brief introduction.

1. Automatic configuration

@SpringBootApplication
@EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
@EnableJpaAuditing(auditorAwareRef = "auditorAwareImpl")
public class EnversDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(EnversDemoApplication.class, args);
    }
}

The @ enablejparesites (RepositoryForyForyForyForyClass = enversRevisionRepositoryForyBean. Class) configuration here indicates that the Envers module is opened.

2.Audited comments

@Entity
@Audited
public class Book extends AuditableEntity{

    @javax.persistence.Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String title;

    private String author;

    private String description;

    private long price;

    private boolean valid;

    // getter and setter
}

Use @Audited to mark that this entity class needs auditing.

Inherit RevisionRepository

public interface BookDao extends RevisionRepository<Book, Long, Integer>,JpaRepository<Book, Long> {
}

The query method for finding revisions is obtained by inheriting RevisionRepository, mainly as follows:

@NoRepositoryBean
public interface RevisionRepository<T, ID extends Serializable, N extends Number & Comparable<N>> {
    Revision<N, T> findLastChangeRevision(ID var1);

    Revisions<N, T> findRevisions(ID var1);

    Page<Revision<N, T>> findRevisions(ID var1, Pageable var2);

    Revision<N, T> findRevision(ID var1, N var2);
}

N here refers to the type of change version number. Integer is generally enough. If it is not enough, it can be changed to Long type. T here is the entity class. ID is the primary key type of the entity class.

Query changes

After the above configuration, each version of the change can be recorded normally and can be queried by the following methods, such as:

Revisions<Integer,Book> revision = bookDao.findRevisions(id);
List<Revision<Integer,Book>> data = revision.getContent();

The id here is the id of the entity.

Table Structure of revision

Hibernate records the version of each change by default with the entity class suffix _AUD, for example

-- ----------------------------
--  Table structure for book_aud
-- ----------------------------
DROP TABLE IF EXISTS "public"."book_aud";
CREATE TABLE "public"."book_aud" (
    "id" int8 NOT NULL,
    "rev" int4 NOT NULL,
    "revtype" int2,
    "author" varchar(255) COLLATE "default",
    "description" varchar(255) COLLATE "default",
    "price" int8,
    "title" varchar(255) COLLATE "default",
    "valid" bool
)
WITH (OIDS=FALSE);
ALTER TABLE "public"."book_aud" OWNER TO "postgres";

-- ----------------------------
--  Primary key structure for table book_aud
-- ----------------------------
ALTER TABLE "public"."book_aud" ADD PRIMARY KEY ("id", "rev") NOT DEFERRABLE INITIALLY IMMEDIATE;

-- ----------------------------
--  Foreign keys structure for table book_aud
-- ----------------------------
ALTER TABLE "public"."book_aud" ADD CONSTRAINT "fk2u9iq76nh69r6f989ae7xft9" FOREIGN KEY ("rev") REFERENCES "public"."revinfo" ("rev") ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE;

If you want to change the table suffix, you can configure it through the property of org.hibernate.envers.audit _ table _ Suffix. The rev field inside indicates the revision version number, which is generally incremented globally. The revtype field indicates the type of operation, 0 indicates addition, 1 indicates update, and 2 indicates deletion.

Another table is revinfo, which records the version number and time of each change:

-- ----------------------------
--  Table structure for revinfo
-- ----------------------------
DROP TABLE IF EXISTS "public"."revinfo";
CREATE TABLE "public"."revinfo" (
    "rev" int4 NOT NULL,
    "revtstmp" int8
)
WITH (OIDS=FALSE);
ALTER TABLE "public"."revinfo" OWNER TO "postgres";

-- ----------------------------
--  Primary key structure for table revinfo
-- ----------------------------
ALTER TABLE "public"."revinfo" ADD PRIMARY KEY ("rev") NOT DEFERRABLE INITIALLY IMMEDIATE;

Custom revision entity

If the implementation of the default envers does not meet your requirements, use the @RevisionEntity annotation, replace @Audited, and then customize the listener, for example

@Entity
@RevisionEntity( ExampleListener.class )
public class ExampleRevEntity extends DefaultRevisionEntity {
    private String username;

    public String getUsername() { return username; }
    public void setUsername( String username ) { this.username = username; }
}
public class ExampleListener implements RevisionListener {

    public void newRevision( Object revisionEntity ) {
        ExampleRevEntity exampleRevEntity = ( ExampleRevEntity ) revisionEntity;
        Identity identity =
            (Identity) Component.getInstance( "org.jboss.seam.security.identity" );

        exampleRevEntity.setUsername( identity.getUsername() );
    }
}

I won’t go into details here. Please refer to hibernate for details.

doc