Professional Documents
Culture Documents
Castro (@CastroAlexandre) Consultor (Summa) e Instrutor (Globalcode) SCJP, SCWCD, SCBCD, SCEA-I, SCSNI
Motivao
Rastrear o histrico de mudanas de entidades para saber quem, quando e o que foi alterado.
OK, EXIJO O DIREITO DE ALEGAR INSANIDADE.
Hibernate Envers
API para auditar classes de persistncia Baseado no conceito de revises similiar ao Subversion Cada transao gera uma reviso
3.5
...
...
...
...
ENVERS
Configurao
Configure os event listeners do Hibernate Envers no persistence.xml Anote as classes ou os atributos da classe com @Audited
Configurao no persistence.xml
<property name="hibernate.ejb.event.post-insert" value="org.hibernate.ejb.event.EJB3PostInsertEventListener, org.hibernate.envers.event.AuditEventListener" /> <property name="hibernate.ejb.event.post-update" value="org.hibernate.ejb.event.EJB3PostUpdateEventListener, org.hibernate.envers.event.AuditEventListener" /> <property name="hibernate.ejb.event.post-delete" value="org.hibernate.ejb.event.EJB3PostDeleteEventListener, org.hibernate.envers.event.AuditEventListener" /> <property name="hibernate.ejb.event.pre-collection-update" value="org.hibernate.envers.event.AuditEventListener" /> <property name="hibernate.ejb.event.pre-collection-remove" value="org.hibernate.envers.event.AuditEventListener" /> <property name="hibernate.ejb.event.post-collection-recreate" value="org.hibernate.envers.event.AuditEventListener" />
Configurao na classe
@Entity @Audited public class City { @Id @GeneratedValue private int id; private String name; @ManyToOne private State state;
// CONSTRUCTORS // GETTERS AND SETTERS // ETC...
@Entity public class City { @Id @GeneratedValue private int id; @Audited private String name; @Audited @ManyToOne private State state;
// CONSTRUCTORS // GETTERS AND SETTERS // ETC...
} }
As tabelas City_AUD e State_AUD sero criadas automaticamente para armazenar o histrico de mudanas das entidades City e State respectivamente.
Configurao na classe
O nome da tabela que guarda o histrico de mudanas pode ser alterado com o uso da anotao @AuditTable
@Entity @Audited @AuditTable( "TB_City_AUDIT" ) public class City { @Id @GeneratedValue private int id; private String name; @ManyToOne private State state; // CONSTRUCTORS // GETTERS AND SETTERS // ETC... }
<property name="org.hibernate.envers.audit_table_prefix" value=TB_" /> <property name="org.hibernate.envers.audit_table_suffix" value="_AUDIT" />
@Audited
DEMO
Configurao da RevisionEntity
@Entity @RevisionEntity( MyRevisionListener.class ) public class MyRevisionEntity extends DefaultRevisionEntity { private String user; public String getUser() { return user; } public void setUser( final String user ) { this.user = user; }
} public class MyRevisionListener implements RevisionListener { public void newRevision( final Object revisionEntity ) { ( (MyRevisionEntity) revisionEntity ).setUser( "Castro" ); } }
Recuperando revises
O histrico de mudanas tem duas dimenses: A primeira (Horizontal) o estado do banco de dados em uma dada reviso. A segunda (Vertical) so revises de cada entidade alterada. O que pode ser recuperado: Revises da Entidade
Entidades da Reviso
Entidades e Revises
ENT. A ENT. B ENT. C
ENTIDADES
REV. 1
id = 1 name = "A"
id = 2 name = "B"
id = 3 name = "C"
REV. 2
id = 2 name = "BX"
REV. 3
id = 1 name = "AX"
id = 2 name = "BY"
REVISES
Entidades da Reviso
ENT. A ENT. B ENT. C
ENTIDADES
REV. 1
id = 1 name = "A"
id = 2 name = "B"
id = 3 name = "C"
REVISO 1
REV. 2
id = 2 name = "BX"
REV. 3
id = 1 name = "AX"
id = 2 name = "BY"
REVISES
Entidades da Reviso
ENT. A ENT. B ENT. C
ENTIDADES
REV. 1
id = 1 name = "A"
id = 2 name = "B"
id = 3 name = "C"
REV. 2
id = 1 name = "A"
id = 2 name = "BX"
id = 3 name = "C"
REVISO 2
REV. 3
id = 1 name = "AX"
id = 2 name = "BY"
REVISES
Revises da Entidade
ENT. A ENT. B ENT. C
ENTIDADES
REV. 1
id = 1 name = "A"
id = 2 name = "B"
id = 3 name = "C"
REV. 2
id = 2 name = "BX"
REV. 3
id = 1 name = "AX"
id = 2 name = "BY"
ENTIDADE B REVISES
Revises da Entidade
ENT. A ENT. B ENT. C
ENTIDADES
REV. 1
id = 1 name = "A"
id = 2 name = "B"
id = 3 name = "C"
REV. 2
id = 2 name = "BX"
id = 3 name = "C"
REV. 3
id = 1 name = "AX"
id = 2 name = "BY"
id = 3 name = "C"
ENTIDADE C REVISES
Recuperando Revises
O histrico de mudanas pode ser recuperado atravs de queries semelhantes ao Hibernate Criteria A criao das queries realizada atravs de um org.hibernate.envers.AuditReader
AuditReader reader = AuditReaderFactory.get( entityManager );
Recuperando Revises
City oldCity = getAuditReader.find( City.class, cityId, revision );
Recupera a entidade City com o id especificado na reviso informada, se a entidade no existir na reviso informada retorna null, se apenas algumas propriedades foram anotadas com @Audited apenas os dados dessas propriedades sero populados as demais propriedades no auditadas recebem null.
Recuperando Revises
Number revisionCount = (Number) getAuditReader() .createQuery() .forRevisionsOfEntity( City.class, false, true ) .setProjection( AuditEntity.revisionNumber().count() ) .getSingleResult();
Recuperando Revises
List<Object> result = getAuditReader() .createQuery() .forRevisionsOfEntity( City.class, false, true ) .add( AuditEntity.property( "name" ).eq( "X" ) ) .getResultList();
DEMO
Resumindo
Hibernate Envers...
... no intrusivo ... transparente ... baseado em revises ... fcil de usar ... permite adicionar metadados para cada reviso ... permite pesquisar o histrico de mudanas atravs de critrios
Q&A
Referncias
http://www.jboss.org/envers
THANKS!