Patterns and Anti-Patterns in Hibernate Patrycja Wegrzynowicz CTO, Yonita, Inc. CTO, Yon Labs and...

Preview:

Citation preview

Patterns and Anti-Patterns in Hibernate

Patrycja WegrzynowiczCTO, Yonita, Inc.CTO, Yon Labs and Yon Consulting, LLC

About me

Past• 10+ years of practical experience as software developer, architect, and

head of software R&D

• PhD in Computer Science (automated code analysis)

• Speaker at JavaOne, JavaZone, Devoxx, Jazoon, OOPSLA, and others

Present• Founder and CTO of Yonita Inc. and Yon Consulting

• Bridge the gap between the industry and the academia

Future• Who cares? Seize the day!

Agenda

Transactional issues

Break

Object-oriented issues

Break

Performance issues

Break

Automated detection

Usage Aspects of Hibernate

Architecture

Object-OrientedDesign

Relational DB

Design

Programming

CaveatEmptor Demo

Java Persistence with

Hibernate• Christian Bauer

• Gavin King

CaveatEmptor• Demo in the book

• Simple auction system

TRANSACTIONAL ISSUES

First and Foremost, Correctness

Warranty of correctness• A piece of code always produces an expected result

Scenarios• Various inputs

• Concurrency

• Time line

Is CaveatEmptor Correct?

tran

sact

ion

CaveatEmptor – Concurrent Scenario

Thread A – new bid 9999

// begin transaction

// two bids in the db: 100, 124

Bid curMinBid = itemDAO.getMinBid(itemId);

Bid curMaxBid = itemDAO.getMaxBid(itemId);

// curMaxBid = 124

// get locked item// item with two bids: 100, 124

// curMaxBid = 124Item item = itemDAO.findById(itemId, true);

Bid newBid = item.placeBid(…, newAmount,

curMaxBid, curMinBid);

// commit transaction

Thread B – new bid 1000

// begin transaction

// two bids in db: 100, 124

Bid curMinBid = itemDAO.getMinBid(itemId);

Bid curMaxBid = itemDAO.getMaxBid(itemId);

// curMaxBid = 124

// get locked item// item with three bids: 100, 124, 9999

// but curMaxBid = 124Item item = itemDAO.findById(itemId, true);Bid newBid = item.placeBid(…, newAmount,

curMaxBid, curMinBid);

// commit transaction

Two bids in the database: 100, 124

1 2

3 4

successful bid: 9999 successful bid: 1000

How to Fix It?

REPEATABLE_READS

SERIALIZABLE

HIBERNATE VERSIONING

YES

NO

NO

YES

CaveatEmptor – Hibernate Versioning

Thread A – new bid 9999

// begin transaction

// two bids in the db: 100, 124

Bid curMinBid = itemDAO.getMinBid(itemId);

Bid curMaxBid = itemDAO.getMaxBid(itemId);

// curMaxBid = 124

// get item (version 1)// item with two bids: 100, 124

// curMaxBid = 124Item item = itemDAO.findById(itemId, true);

Bid newBid = item.placeBid(…, newAmount,

curMaxBid, curMinBid);

// commit transaction (version 2)

Thread B – new bid 1000

// begin transaction

// two bids in db: 100, 124

Bid curMinBid = itemDAO.getMinBid(itemId);

Bid curMaxBid = itemDAO.getMaxBid(itemId);

// curMaxBid = 124

// get item (version 2)// item with three bids: 100, 124, 9999

// but curMaxBid = 124Item item = itemDAO.findById(itemId, true);Bid newBid = item.placeBid(…, newAmount,

curMaxBid, curMinBid);

// commit transaction (version 3)

Two bids in the database: 100, 124

1 2

3 4

successful bid: 9999 successful bid: 1000

CaveatEmptor – Repeatable Reads

Thread A – new bid 9999

// begin transaction

// two bids in the db: 100, 124

Bid curMinBid = itemDAO.getMinBid(itemId);

Bid curMaxBid = itemDAO.getMaxBid(itemId);

// curMaxBid = 124

// get item (version 1)// item with two bids: 100, 124

// curMaxBid = 124Item item = itemDAO.findById(itemId, true);

Bid newBid = item.placeBid(…, newAmount,

curMaxBid, curMinBid);

// commit transaction (version 2)

Thread B – new bid 1000

// begin transaction

// two bids in db: 100, 124

Bid curMinBid = itemDAO.getMinBid(itemId);

Bid curMaxBid = itemDAO.getMaxBid(itemId);

// curMaxBid = 124

// get item (version 2)// item with two bids loaded: 100, 124

// but curMaxBid = 124Item item = itemDAO.findById(itemId, true);Bid newBid = item.placeBid(…, newAmount,

curMaxBid, curMinBid);

// commit transaction (version 3)

Two bids in the database: 100, 124

1 2

3 4

successful bid: 9999 successful bid: 1000

CaveatEmptor - Repeatable Reads

Even worse• MySQL takes a snapshot of the database at the moment of the first

query

CaveatEmptor - Serializable

SERIALIZABLE works fine• All transactions occur in a completely isolated fashion; i.e., as if all

transactions in the system had executed serially, one after the other

• Snapshot isolation or lock-based concurrency control (read/write

locks released at the end of a transaction, range-locks)

What about performance?• Can you imagine eBay working this way?

CaveatEmptor - Re-Ordering

CaveatEmptor - Re-Ordering

Item class

• Represents item and

auction; has the list of bids

Why to inject min and max

bids (internal state) to an

item?

Back to OO Principles

• Objects should contain

their internal state

Alternative Approaches

Calculate maximum in Java

• Safe, but requires loading of all the bids

Keep track of the winning bid

• Manual tracking, but with encapsulation

• Db denormalized, but fast

Utilize custom mappings with custom queries,

laziness, order or where clauses

• Db normalized, as fast as the present code

18

Alternative AproachesInverse Mappings with Embedded Queries

<set name=„maxBids" inverse="true" lazy=„true"> <key not-null="true"> <column name="ITEM_ID"/> </key> <one-to-many class="Bid"/>

<loader query-ref="getMaxBid"/></set>

> Automated object state– Encapsulation

> Inverse– Makes use of present

relations– Normalized form

> Lazy– Loaded on the first access

> Custom queries– SQL – Use order-by and where if

they are enough

Puzzle #1 getItemMaxBid

select b

from Bid b

where b.amount.value =

(select max(b.amount.value)

from Bid b

where b.item.id = :itemid)

Puzzle #1 getItemMaxBid – Hint

Item #1• Bid $100

• Bid $125

• Bid $150

Item #2• Bid $20

• Bid $125

select b

from Bid b

where b.amount.value =

(select max(b.amount.value)

from Bid b

where b.item.id = :itemid)

Puzzle #1 getItemMaxBid – Answer

Item #1• Bid $100

• Bid $125

• Bid $150

Item #2• Bid $20

• Bid $125

getItemMaxBid(Item#2)• Item #1 Bid $125

• Item #2 Bid $125

select b

from Bid b

where b.amount.value =

(select max(b.amount.value)

from Bid b

where b.item.id = :itemid)

Puzzle #1 getItemMaxBid – Fixed

Item #1• Bid $100

• Bid $125

• Bid $150

Item #2• Bid $20

• Bid $125

getItemMaxBid(Item#2)• Item #2 Bid $125

select b

from Bid b

where b.amount.value =

(select max(b.amount.value)

from Bid b

where b.item.id = :itemid)

–and b.item.id = :itemid

Puzzle #2 placeBid

Puzzle #2 placeBid – Hint

Puzzle #2 placeBid – Fixed

>=

OBJECT-ORIENTED ISSUES

What is OO about?

Basic Principles

• Data abstraction = data + behavior

• Encapsulation, inheritance, polimorphism

Advanced Principles (SOLID)

• Single Responsibility Principle

• Open/Closed Principle

• Liskov Substitution Principle

• Interface Segregation Principle

• Dependency Inversion Principle

[…]

[…]

[…]

[…]

Is This a Good OO Model?

[…]

[…]

[…]

[…]

Anemic Domain Model!

Is This a Good OO Model?

Rich OO Model – CaveatEmptor

[…][…]

[…]

[…]

CaveatEmptor – A Closer Look

We Need Encapsulation!

We can add to the mutable listwhatever we like.

We can add a bid to the item witha different item reference.

Without Encapsulation, Business Methods Are Only Lipstick on a Pig

Exposed Structure Results in Bad Things

Inconsistent state of objects• The winning bid for an item which is not maximal

• The winning bid added after the auction ended

• Basically, we cannot trust our data!

Various Bugs• Null pointer exceptions

• Nasty bugs (unexpected nulls, consider embedded objects!)

Too much code• Duplicated code, defensive code, spaghetti code

Practices to Code for EncapsulationRestrive Access Modifiers

private, package, protected

fields, getters, setters

• used by hibernate or to manage referential integrity

hibernate is able to deal with any access modifiers

(even private!) of the members of a class

Practices to Code for EncapsulationConsistent Management of Internal State

All roads lead to Rome

// custom example!public Item(MonetaryAmount initialPrice) {

// beware of polymorphic calls in constructors// it’s better to use a private _setInitialPrice from both the setter and ctrsetInitialPrice(initialPrice);

}public void setInitialPrice(MonetaryAmount initialPrice) {

if (initialPrice == null) throw new IllegalArgumentException(„initial price cant be null”);this.initialPrice = initialPrice;

}

Practices to Code for EncapsulationDo Not Expose Mutable Internal State

Problems mainly in the case of Date and Collection hierarchies• return date; // Date

• return bids; // List<Bid>

• Uncontrolled changes to the internal state of an object Defensive copying

• return new Date(created.getTime());

• return new ArrayList(bids);

• Inefficient for collections – we force the retrieval of the bids from the database

Immutable• return Collections.unmodifiableList(bids);

• Inefficient for persistent collections mapped by property as dirty checking compares collections by identity

38

Practices to Code for EncapsulationImmutable Collection Returned

> Dirty checking compares identity of collections– Additional statements issued– Embedded objects – recreation of the collection– List of entities – all entities updated

> Practices– Internally, do not create new collections, reuse the one retrieved– Use field mapping, or– Use different accessors for public access and hibernate access

Practices to Code for Encapsulation

Business first

• First business methods, than accessors

Restrictive access modifiers

• Hibernate can deal with private/package/protected

Don't expose mutable internal state

• Problems mainly in the case of Date and Collections

• return date; // Date

• return bids; // List<Bid>

• Uncontrolled changes to the internal state of an object

Puzzle #3 Immutable List

Puzzle #3 Immutable List - Hint

item.setBids(item.getBids())?

Puzzle #3 Immutable List - Answer

item.setBids(item.getBids())?The answer: bids = empty list

PERFORMANCE ISSUES

This is Java.

Is Java Slow?

On most Intels Java is as fast or faster than C• The Gaia Satellie and Data Processing

• William O’Mullane from ESAC

• Jazoon 2010

Is Hibernate Slow?

Sometimes…• Depending on usage scenarios

Puzzle #4 Standard Collection Mapping

Puzzle #4 Standard Collection Mapping

Puzzle #4 Standard Collection Mapping

Puzzle #5 Immutable Collections

Puzzle #5 Immutable Collections – Hint

Puzzle #5 Immutable Collection

Inheritance Strategies

> Table per class hierarchy– One table

> Table per subclass– Four tables

> Table per concrete class– Two tables

A<<abstract>>

B<<abstract>>C

D

Inheritance Strategies in Hibernate

Constraints Direct Access Polymorphism

Table per Class Hierarchy

Sometimes impossible to add db

constrains(e.g. not null)

FastPolymorphic searchPolymorphic relations

Table per Subclass Constraints possible Slower (joins)

Polymorphic searchPolymorphic relations

Table per Concrete Class Constraints possible Fast

Polymorphic search with unions or N

queries

+

+ +

+ +

+

!

!

÷

AUTOMATED DETECTION OF HIBERNATE ISSUES

Code Level

Code Level Analysis

Code Level Analysis

Automated Detection of Code Issues

+

Automated code analysis

Definions of transactional,security, performance anti-

patterns

Semantic Code Query System

Code query systems• Explore relationships among program elements

• Structural and call-related predicates

• CodeQuest, JQuery

Semantic code query systems• Focus on behavior (in-depth data flow analysis)

• Behavioral predicates in addition to structural ones

• D-CUBED – my PhD thesis (focus on design patterns)

• Yonita – rewrite + queries

Yonita

Automated code analysis

• Semantic code query system

• Focus on behavior, not only structure

• Metamodel of a program: instances, structure, behaviour

(calls, input/output values, execution paths)

Definitions of various issues/anti-patterns

• Catalog of issues

• Transactions, object-oriented design, security, performance,

multithreading

How does Yonita work?

Analyses

Parser

Store

Query

BytecodeSources

asm, Recoder

analyses: structural, call flow, data flowtransitive closures

relational (MySQL) or deductive (XSB) database

SQL or Prolog(anti-)patternsbugsvulnerabilities...

Metamodel

Structural elements• Very similar to CodeQuest and Jquery

• Statements

Instances• Symbolic instances

Behavioral predicates supporting call and data flows• Output and input values

• Assignments

Instances

Null

New

This

Parameter

Exception

Multiple

ReturnInstance

ParamInstance

ThisInstance

NewInstance

NullInstance

Except.Instance

Instance Instance …

Instance … Instance …

Summary

Proper usage of hibernate is tricky• Transactional issues and correctness of code under various scenarios

• Maintanability and basic object-oriented principles

• Efficiency of code and mappings

Automatization can help

Contact

Patrycja• patrycja@YonLabs.com

• twitter.com/YonLabs

Yonita• http://www.Yonita.com

• http://www.YonLabs.com

• http://www.YonConsulting.com