envers_devoxx.pdf

47
www.devoxx.com 1

Upload: marcio-bruno

Post on 03-Jun-2018

215 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 1/47

www.devoxx.com

1

Page 2: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 2/47

www.devoxx.com

EnversEasy Entity  Versioning Auditing

 Adam WarskiSoftware EngineerLevel N Consulting

2

Page 3: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 3/47

www.devoxx.com

Who am I?

 Adam Warski :)

Formerly at JBoss

Senior Software Engineer at Level N Consulting

Creator of Envers

http://www.warski.org/blog (Envers, Seam, Typestate, ...)

3

3

Page 4: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 4/47

www.devoxx.com4

Overview of patterns for auditing

What is Envers?

How does it work?

Configuration

 An example

QueriesUse cases

Using Envers

 Agenda

4

Page 5: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 5/47

www.devoxx.com

Overview of patterns forauditing

What’s the problem and how to approach it?

5

Page 6: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 6/47

www.devoxx.com6

Example: Person & Address

We want to store the history of a Person's addresses

6

Page 7: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 7/47

www.devoxx.com7

Logging all activity to a file or database

Entity state: String or CSV

Very simple

Hard to read historic data

Patterns: Audit Log

7

Page 8: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 8/47

www.devoxx.com8

Explicit start and end date (validity) Verbose

“Manual”

Complicates mapping

Patterns: E! ectivity

8

Page 9: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 9/47

www.devoxx.com9

Getter with a Date argument

Complicates mapping; facades needed

Verbose

When more properties are temporal: temporal object /

snapshot

Patterns: Temporal property

9

Page 10: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 10/47

www.devoxx.com10

Patterns overall

In most use cases and most of the time:

we are only interested in “current” data

Historical data:

much less often

in different places - uniform access not a necessity

10

Page 11: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 11/47

Page 12: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 12/47

www.devoxx.com12

What is Envers?

 An entity auditing (versioning) library

Part of Hibernate

Simplifies storing and retrieving historical data

12

Page 13: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 13/47

www.devoxx.com13

 Assumptions

Transparent: data can be used as always (queried,persisted, etc.)

Not intrusive:

The database schema isn’t changed (some tables can beadded)

Minimal code changes

Slowly changing data

13

Page 14: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 14/47

www.devoxx.com14

The programmer specifies which entities should beaudited

For each audited entity, an audit entity is (dynamically)created

e.g. entity “Address” has an “Address_AUD” companion

The companion stores historical data

How does Envers work?

14

Page 15: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 15/47

www.devoxx.com15

On an update/insert/delete: data inserted to audit tables

 All changes in a transaction: 1 revision

Revisions capture consistent state

Revisions are global

Similar to SVN

How does Envers work?

15

Page 16: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 16/47

www.devoxx.com16

To make an entity audited:annotate with @Audited 

 Add event listeners topersistence.xml

Envers Configuration

16

Page 17: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 17/47

www.devoxx.com17

Mappings defined by JPA:

Simple properties: Strings, Integers, Dates, ...

Components

Relations

Some Hibernate extensionsCustom types

Collections

What can be audited?

17

Page 18: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 18/47

www.devoxx.com18

Person & Address example

! Now let's assume that both entities are annotated with@Audited 

18

Page 19: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 19/47

www.devoxx.com

// Revision 1

em.getTransaction().begin(); Address a1 = new Address(“West st.”, 10);

 Address a2 = new Address(“East st.”, 15);

Person p = new Person(“John”, “Doe”);

 p.setAddress(a1);

entityManager.persist(a1);

entityManager.persist(a2);

entityManager.persist( p);

em.getTransaction().commit();

19

Page 20: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 20/47

www.devoxx.com

// Revision 2

em.getTransaction().begin(); p = entityManager.find(Person.class, id );

 p.setName(“Paul”);

 p.setAddress(a2);

em.getTransaction().commit();

Old person data is storedNo code changes - completely transparent to the user

20

Page 21: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 21/47

www.devoxx.com

 AuditReader ar = AuditReaderFactory.get(em);

// Reading the person at revision 1old_p = ar.find(Person.class, id , 1);

assert “John”.equals(old_p.getName());

assert a1.equals(old_p.getAddress());

Transparent traversing of relations

21

Page 22: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 22/47

www.devoxx.com

// Reading the addresses at revision 1

old_a1 = ar.find(Address.class, a1_id , 1);assert old_a1.getPersons().size() == 1;

assert old_a1.getPersons().contains( p);

old_a2 = ar.find(Address.class, a2_id , 1);

assert old_a2.getPersons().size() == 0;

Transparent traversing of relations: also in case ofcollections

22

Page 23: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 23/47

www.devoxx.com

Querying

How to query historical data?

23

Page 24: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 24/47

www.devoxx.com

24

Page 25: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 25/47

www.devoxx.com

25

Page 26: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 26/47

www.devoxx.com

26

Page 27: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 27/47

www.devoxx.com

27

Page 28: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 28/47

www.devoxx.com28

Entities-at-revision

Revisions-of-entity

Inspired by criteria queries

Querying

auditReader.createQuery().forRevisionsOfEntity(Person.class, false, true).addProjection(AuditEntity.revisionNumber().count())

.add (AuditEntity.id().eq( person.getId())).getSingleResult()

28

Page 29: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 29/47

www.devoxx.com29

With each revision, arbitrary data can be bound (metadata)

For example: user making the changes

Special entity ( @RevisionEntity ), storing the metadata

Listener, invoked when a new revision is created

Logging data for revisions

29

Page 30: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 30/47

www.devoxx.com

Use-cases

Envers in practice

30

Page 31: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 31/47

www.devoxx.com31

The power of wikis: everybody can edit

It works well, because history is stored and viewable byeveryone

Plus, you know who made the changes

What if the editable part of your website is more than just

one textbox?

e.g. a set of links, images

Use case: Structured Wiki

31

Page 32: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 32/47

www.devoxx.com32

@Entity@Audited 

 public class WikiPage {

@Id @GeneratedValue  private Long id;

 private String title;

 private String content;

@CollectionOfElements private Set<String>links;

@OneToMany private Set<Image> images;

}

Step 1: main entity

32

Page 33: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 33/47

www.devoxx.com33

Step 2: revision entity

@Entity@RevisionEntity(WikiListener.class)

 public class WikiRevision {

@Id @GeneratedValue @RevisionNumber  private Long id;

@RevisionTimestamp private Longtimestamp;

@ManyToOne private User modifiedBy;

// (...)

}

33

Page 34: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 34/47

www.devoxx.com34

Step 3: revision listener

 public class WikiListener im  plementsRevisionListener {

   public void  newRevision(Object revEntity) {

  WikiRevision wikiRev = (WikiRevision)

revEntity;

  User currentUser = (User)Component.getInstance("currentUser");

   wikiRev.setModifiedBy(currentUser);

  }

}

34

Page 35: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 35/47

www.devoxx.com35

Step 4: paginating history

 public List getHistory(int from , int count,Long pageId ) {

return auditReader.createQuery()

 .forRevisionsOfEntity(WikiPage.class,

false, true)

.addOrder(revisionNumber ().desc())

 .add(id().eq ( pageId ))

 .setFirstResult(from )

 .setMaxResults(count)

 .getResultList();

}35

Page 36: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 36/47

www.devoxx.com36

Changes by user

 public List getChangesByUser(User user) {

return auditReader.createQuery()

 .forRevisionsOfEntity(WikiPage.class, false,true)

.addOrder(revisionNumber ().desc())

 .add(revisionProperty( "modifiedBy").eq (user))

 .getResultList();

}

36

Page 37: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 37/47

www.devoxx.com37

We add a field to WikiPage: verified 

We want to find the latest verified version of a page

Simple tagging

auditReader.createQuery()

 .forRevisionsOfEntity(WikiPage.class, false,true)

.add(revisionNumber().maximize()

  .add( property( "verified").eq (true))

  .add(id().eq ( pageId )))

 .getResultList();

37

Page 38: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 38/47

www.devoxx.com

Practical

38

Page 39: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 39/47

www.devoxx.com

How to use Envers?

Works everywhere where Hibernate works

Standalone, Webapps, Seam, Spring, ...

Formerly a stand-alone project

1.1.0.GA released in October

Now part of Hibernate

Next release in 1-2 months

39

39

Page 40: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 40/47

www.devoxx.com

How to use Envers?

Download from:

40

 Also in JBoss Snapshot repository:

http://www.jboss.org/envers

http://www.jboss.org/community/docs/DOC-11381

40

Page 41: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 41/47

www.devoxx.com41

 Your data is safe!

41

Page 42: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 42/47

www.devoxx.com42

Must be slower than without auditing:

1 insert for each modified entity

1 insert for each transaction

Performance

MySQL 5.1.30

(InnoDB)

5000

inserts

1000

complex inserts

5000

updates

Not audited

 Audited

Difference

6.307s 6.622s 8.487s

9.807s 12.758s 11.444s

x 1.55 x 1.92 x 1.34

42

Page 43: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 43/47

www.devoxx.com43

Unchanged mapping ( not intrusive ) Unchanged code ( transparent ) Straightforward history reading

Deleted entities aren't gone

Easier to use ( @Audited  ) Data for revisions

Queries

Envers overall

43

Page 44: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 44/47

www.devoxx.com

Future

Support for other Hibernate-specific mappings

relations in components

collections of components

JPA2

44

44

Page 45: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 45/47

www.devoxx.com

Future

Tools

import

revert

branch

DIFF

Different auditing strategies

storing only fields

45

45

Page 46: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 46/47

www.devoxx.com

Future

Tagging

a tag can be anything

only one revision can

be tagged (many?)

find entity by tag

46

46

Page 47: envers_devoxx.pdf

8/12/2019 envers_devoxx.pdf

http://slidepdf.com/reader/full/enversdevoxxpdf 47/47

 Thank you for yourattention!

http://www.jboss.org/envers/ [email protected]