Thursday, October 26, 2017

Hibernate Inheritance Mapping

Inheritance

MappedSuperclass

Totally separated tables in database. Two tables will be created for DebitAccount and CreditAccount. No fetching against subclass is available.

@MappedSuperclass
public static class Account {
 
    @Id
    private Long id;
 
}
 
@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}

Single Table (default choice for JPA)

Each subclass in a hierarchy must define a unique discriminator value, which is used to differentiate between rows belonging to separate subclass types. If this is not specified, the DTYPE column is used as a discriminator, storing the associated subclass name.

@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}

@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorFormula(
    "case when debitKey is not null " +
    "then 'Debit' " +
    "else ( " +
    "   case when creditKey is not null " +
    "   then 'Credit' " +
    "   else 'Unknown' " +
    "   end ) " +
    "end "
)
//@DiscriminatorColumn(
//    name="type",
//    discriminatorType=DiscriminatorType.STRING)
// only STRING, CHAR, INTEGER are valid
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
@DiscriminatorValue(value = "Debit")
public static class DebitAccount extends Account {
 
    private String debitKey;
}
 
@Entity(name = "CreditAccount")
@DiscriminatorValue(value = "Credit")
public static class CreditAccount extends Account {
 
    private String creditKey;
}


@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorValue( "null" )
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
@DiscriminatorValue( "Debit" )
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
@DiscriminatorValue( "Credit" )
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
 
}
 
@Entity(name = "OtherAccount")
@DiscriminatorValue( "not null" )
public static class OtherAccount extends Account {
 
    private boolean active;
}

Joined Table

Tables for subclasses will have a foreign key column that points back to superclass.

@Entity(name = "Account")

@Inheritance(strategy = InheritanceType.JOINED)
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}


@Entity(name = "Account")

@Inheritance(strategy = InheritanceType.JOINED)
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
@PrimaryKeyJoinColumn(name = "account_id")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
@PrimaryKeyJoinColumn(name = "account_id")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}

Table per (concrete) class

@Entity(name = "Account")

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public static class Account {
 
    @Id
    private Long id;
}
 
@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {
 
    private BigDecimal overdraftFee;
}
 
@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {
 
    private BigDecimal creditLimit;
}

Immutable

Hibernate skips any updates if the @Immutable has been used.
@Entity(name = "Batch")
public static class Batch {

    @Id
    private Long id;

    private String name;

    @OneToMany(cascade = CascadeType.ALL)
    @Immutable
    private List<Event> events = new ArrayList<>( );

    //Getters and setters are omitted for brevity

}

@Entity(name = "Event")
@Immutable
public static class Event {

    @Id
    private Long id;

    private Date createdOn;

    private String message;

    //Getters and setters are omitted for brevity

}


Wednesday, October 25, 2017

Hibernate EntityManager Important Concepts

Entity States in a Persistence Context

transient

the entity has been initiated but is not associated with a persistence context, typically not identifier has been assigned

managed/persistent

the entity has an associated identifier and is associated with a persistence context

detached

the entity has an associated identifier but is not associated with a persistence context

removed

the entity has an associated identifier and is associated with a persistence context, however it is scheduled for removal from the database.

Flushing

When the flush() of an EntityManager is called, it synchronizes the state of the persistence context with the underlying database.

By default, Hibernate uses the AUTO flush mode, a flush is  triggered automatically when:
  • prior to committing a Transaction
  • prior to executing a JPQL/HQL query that overlaps with the queued entity actions (inserts, updates, deletes etc.)
  • before executing any native SQL query that has not registered synchronization

Flushing Operation Order

The order in which SQL statements are executed is given by the ActionQueue and not by the order in which entity state operations have been previously defined. 

The ActionQueue executes all operations in the following order:

  1. OrphanRemovalAction
  2. EntityInsertAction or EntityIdentityInsertAction
  3. EntityUpdateAction
  4. CollectionRemoveAction
  5. CollectionUpdateAction
  6. CollectionRecreateAction
  7. EntityDeleteAction

Caching

HibernateSessionacts as a transaction-level cache of persistent data. Once an entity becomes managed, that object is added to the internal cache of the current persistence context (EntityManager or Session). The persistence context is also called the first-level cache, and it’s enabled by default.
Hibernate provides integration with various caching providers for the purpose of caching data outside the context of a particular Session.  It is called the second-level cache.

EntityManager Operations

entityManager.persist( person ); //if FlushModeType is commit, then wait till a flush to save data to database
entityManager.remove( person );
entityManager.getReference( Person.class, personId ); // Not loaded yet
entityManager.find( Person.class, personId );
entityManager.flush();
entityManager.refresh( person );
entityManager.merge( person );
entityManager.contains( person );
entityManager.detach( person );
entityManager.clear()

CascadeType

ALL

cascades all entity state transitions

PERSIST

cascades the entity persist operation.

MERGE

cascades the entity merge operation.

REMOVE

cascades the entity remove operation.

REFRESH

cascades the entity refresh operation.

DETACH

cascades the entity detach operation.

Transactional Patterns

session-per-operation

commit after each database call

session-per-request

session-per-conversation

Automatic Versioning
Hibernate can perform automatic optimistic concurrency control for you. It can automatically detect (at the end of the conversation) if a concurrent modification occurred during user think time.
Detached Objects
If you decide to use the session-per-request pattern, all loaded instances will be in the detached state during user think time. Hibernate allows you to reattach the objects and persist the modifications. The pattern is called session-per-request-with-detached-objects. Automatic versioning is used to isolate concurrent modifications.
Extended Session
(session.disconnect())
The Hibernate Session can be disconnected from the underlying JDBC connection after the database transaction has been committed and reconnected when a new client request occurs. This pattern is known as session-per-conversation and makes even reattachment unnecessary. Automatic versioning is used to isolate concurrent modifications and the Session will not be allowed to flush automatically, only explicitly.

Session-per-application (anti-pattern)

The Hibernate Session, like the JPA EntityManager, is not a thread-safe object and it is intended to be confined to a single thread at once.

Enterprise Application Architecture Design Patterns - Domain Logic Patterns, Session State Patterns, Data Source Patterns

Session State Patterns

 For standard enterprise application, session could be stored in:


Client Session State

it is commonly stored as Cookies in browsers.

Server Session State

it is commonly stored in a clustered cache such as ones provided by JBoss, WebSphere application servers.

Database Session State

It is a database or other data store. For big data solutions, optimized data stores such as Cassandra could be used to handle the high throughput and data volume that traditional databases may not be able to perform well.

Domain Logic Patterns

Transaction Script

Many financial applications may still use stored procedures that put business logic very close to data.
Some simple application may just put all business logic in scripts

Table Module

Some popular frameworks expose an UI that users may hook up tables easily. This kind of mechanisms usually are back up by Table Module that is a single instance that handles the business logic for all rows in a database table.

Domain Model and Service Layer

More complicated applications usually require to start with a domain model first, then a service layer is used to control the abstracted functions that are exposed as services.

Data Source Architectural Patterns

Table Data Gateway

encapsulate the data in a table and its queries in an object, then expose it as a POJO

Row Data Gateway

expose the data in a POJO without any query concerns

Active Record

Incorporate business logic into data access object

Data Mapper

In ORM frameworks, the mapping meta data between objects and tables are stored in separate XML files or annotations. The data is mapped to Entity and Value Object, and many times organized in an aggregate.

Object-Relational Metadata Mapping Patterns

Metadata Mapping

XML files or annotations

Query Object

Object oriented query language that is a wrapper over SQL

Repository

Manages data retrieving functions in a framework core component, in Hibernate/JPA, it is the EntityManager.

Enterprise Application Architecture Design Patterns - Offline Concurrency Locks


Optimistic Offline Lock

it is used when the conflicts are rare. A compensation strategy should be ready when a conflict is found.

In Hibernate, it could be created by using @Version annotation to create a column with version number or a timestamp:


@Entity
public class Flight implements Serializable {
...
    @Version
    @Column(name="version")
    public Integer getVersion() { ... }
}   


@Entity
public class Flight implements Serializable {
...
    @Version
    public Date getLastUpdate() { ... }
} 

Pessimistic Offline Lock

A ReentrantLock could be used inside Java Classes to manage the concurrency control.
In Hibernate, pessimistic offline lock mechanism is also provided:


Session.lock(object, LockMode);


LockMode.WRITE, LockMode.READ could be used.
For Oracle database, two extra lock modes are provided for efficiency:


LockMode.WRITE
acquired automatically when Hibernate updates or inserts a row.
LockMode.UPGRADE
acquired upon explicit user request using SELECT ... FOR UPDATE on databases which support that syntax.
LockMode.UPGRADE_NOWAIT
acquired upon explicit user request using a SELECT ... FOR UPDATE NOWAITin Oracle.
LockMode.READ
acquired automatically when Hibernate reads data under Repeatable Reador Serializable isolation level. It can be re-acquired by explicit user request.
LockMode.NONE
The absence of a lock. All objects switch to this lock mode at the end of a Transaction. Objects associated with the session via a call to update() orsaveOrUpdate() also start out in this lock mode.


Coarse Grained Lock

In term of Domain Driven Design, an aggregate could be a candidate for applying coarse grained lock to reduce the chances of deadlocks.

Implicit Lock

If @Transactional is used in a Spring Framework based application, it could be put into Remote Facade or Session Facade to manage the transaction, then object retrieved from Repository may not need to handle the transaction directly. 

When using Spring @Transactional, please note that:

The Spring team's recommendation is that you only annotate concrete classes with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this will only work as you would expect it to if you are using interface-based proxies. 

Enterprise Application Architecture Design Patterns - Facade vs Gateway vs Proxy

Facade

an object that provides a simplified interface to a larger body of code

Gateway

An object that encapsulates access to an external system or resource.

Proxy

a wrapper or agent object that is being called by the client to access the real serving object behind the scenes

The three patterns are similar in a way that it used to simplify the access to more complicated services, systems or resources etc.

The differences are:

Proxy is usually expose same interface as the real object it represents, it usually locates at the client side and communicates with the real object remotely.

Gateway handles more complicated situations where external systems, resources etc. could be represented as a simplified form. The goal is to encapsulate the implementation details and complexities of external services, libraries, systems, resources etc.

Facade is the opposite of the Gateway pattern, it provides a simplified interface to the objects you own.