Java Persistence API

Basics

  • Each EntityManager instance is associated with a persistence context.
  • A persistence context defines the scope under which particular entity instances are created, persisted, and removed.
  • The EntityManager can be container or application managed.
  • A persistence unit (defined by the persistence.xml) defines a set of all entity classes that are managed by EntityManager instances in an application.
  • EntityManagerFactory instances are thread-safe, EntityManager instances are not
  • persistence.xml -> persistence unit + persistence contenxt -> entity manager factory -> entity manager

Tx

  • <tx:annotation-driven/> only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put <tx:annotation-driven/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services.

Mapping Strategies

A single table per class hierarchy
This strategy provides good support for polymorphic relationships but it requires the columns that contain the state of subclasses to be nullable.

A table per concrete entity class
This strategy provides poor support for polymorphic relationships, and usually requires either SQL UNION queries or separate SQL queries for each subclass for queries that cover the entire entity class hierarchy. Support for this strategy is optional,

Join strategy
Fields or properties that are specific to a subclass are mapped to a different table than the fields or properties that are common to the parent class. This strategy provides good support for polymorphic relationships but has some performance problems.

Multiplicity in Entity Relationships

There are four types of multiplicities: one-to-one, one-to-many, many-to-one, and many-to-many.

Direction in Entity Relationships

The direction of a relationship can be either bidirectional or unidirectional. A bidirectional relationship has both an owning side and an inverse side. A unidirectional relationship has only an owning side. The owning side of a relationship determines how the Persistence runtime makes updates to the relationship in the database.

Bidirectional Relationships

In a bidirectional relationship, each entity has a relationship field or property that refers to the other entity. Through the relationship field or property, an entity class’s code can access its related object. If an entity has a related field, then the entity is said to “know” about its related object. For example, if Order knows what LineItem instances it has and if LineItem knows what Order it belongs to, then they have a bidirectional relationship.

Bidirectional relationships must follow these rules:

  • The inverse (non-owning) side of a bidirectional relationship must refer to its owning side by using the mappedBy element of the @OneToOne, @OneToMany, or @ManyToMany annotation. The mappedBy element designates the property or field in the entity that is the owner of the relationship.
  • The many side of many-to-one bidirectional relationships must not define the mappedBy element. The many side is always the owning side of the relationship.
  • For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key. the non-owning side is marked by the mappedBy element in the relationship annotation.
  • For many-to-many bidirectional relationships either side may be the owning side.
  • Both sides have annotation.

Unidirectional Relationships

In a unidirectional relationship, only one entity has a relationship field or property that refers to the other. For example, LineItem would have a relationship field that identifies Product, but Product would not have a relationship field or property for LineItem. In other words, LineItem knows about Product, but Product doesn’t know which LineItem instances refer to it. The owner side should use the annotation.

Examples

Example 1

From Roster example of JEE tutorial.
Because the relationship between Player (inverse, or non-owning side) and Team is bidirectional, the choice of which entity is the owner of the relationship is arbitrary.

Player(m) - Team(m), Bidirectional
Team(m) - League(1), Bidirectional

public Class Team {
    @ManyToMany
    @JoinTable(name = "EJB_ROSTER_TEAM_PLAYER", joinColumns = @JoinColumn(name = "TEAM_ID", referencedColumnName = "ID")
    , inverseJoinColumns = @JoinColumn(name = "PLAYER_ID", referencedColumnName = "ID")
    )
    public Collection<Player> getPlayers() {
        return players;
    }
 
    @ManyToOne
    public League getLeague() {
        return league;
    }
}
 
public class League{
    @OneToMany(cascade = ALL, mappedBy = "league")
    public Collection<Team> getTeams() {
        return teams;
    }
}
 
public class Player{
    @ManyToMany(mappedBy = "players")
    public Collection<Team> getTeams() {
        return teams;
    }
}

Example 2

From Order example of JEE tutorial.
Order(1) - LineItem(m), Bidirectional

public classOrder{
    @OneToMany(cascade=ALL, mappedBy="order")
    public Collection<LineItem> getLineItems() {
        return lineItems;
    }
}
 
public class LineItem{
    @ManyToOne
        public Order getOrder() {
        return order;
    }
}

Example 3

Self referencing, unidrectional object:

public class Message {
    @Id @GeneratedValue
    private Long id;
 
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "NEXT_MESSAGE_ID")
    private Message nextMessage
}

If we need a bidirectional relationship then we add private Category parentMessage; as well.

Another self referencing relation:

@ManyToOne
public Part getMasterPart() {
    return masterPart;
}
...
@OneToMany(mappedBy="masterPart")
public Collection<Part> getParts() {
    return parts;
}

Joins

select ad from AdDO ad left join ad.adPromotions adp where ad.adStatus != 'ACTIVE' or  adp.paymentStatus != 'PAID'

Caching in Hibernate/JPA

  • The first-level cache is the Session cache and is a mandatory cache through which all requests must pass. The Session object keeps an object under its own power before committing it to the database.
  • Second level cache is an optional cache and first-level cache will always be consulted before any attempt is made to locate an object in the second-level cache. The second-level cache can be configured on a per-class and per-collection basis and mainly responsible for caching objects across sessions.

Concurrency

By default, persistence providers use optimistic locking, where, before committing changes to the data, the persistence provider checks that no other transaction has modified or deleted the data since the data was read. This is accomplished by a version column in the database table, with a corresponding version attribute in the entity class. When a row is modified, the version value is incremented. The original transaction checks the version attribute, and if the data has been modified by another transaction, a javax.persistence.OptimisticLockException will be thrown, and the original transaction will be rolled back. this column should be added manually.

Pessimistic locking goes further than optimistic locking. With pessimistic locking, the persistence provider creates a transaction that obtains a long-term lock on the data until the transaction is completed, which prevents other transactions from modifying or deleting the data until the lock has ended. Pessimistic locking is a better strategy than optimistic locking when the underlying data is frequently accessed and modified by many transactions.

See jdbc

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License