JPA is architecture such that the entity beans must be
attached to the
in order for the entity beans to be
That is, JPA mandates
attach/detach semantics. This has a number of consequences including:
- Developers can't easily take control and persist selected objects
- All attached beans must be in a valid state to flush
- Flush implicitly flushes all dirty state (so dirty state created anywhere flushes implicitly)
- Flush can reorder statements in unexpected ways (causing deadlocks)
- The EntityManager scope must now be managed along with the transaction scope
- No Entity manager, only manage transactions
- Dirty state on each entity bean
- Persisting (save,delete) does not require the PersistenceContext
- PersistenceContext attached to the Transaction
- Partially populated beans always expected
JDBC batch control
With JPA there is:
- No control over JDBC batch size
- No ability to turn off getGeneratedKeys to optimise large inserts
- No ability to turn off cascade behavior (to take full control)
Using JDBC batch is important so that Ebean can get optimal performance when persisting. With Ebean there is a JDBC batch buffer attached to the transaction and can seamlessly batch up persistence calls using JDBC batch.
Ebean provides full control over JDBC batch via the transaction including the
Unlike JPA with Ebean it is easy to fully control and optimise batch processing.
Additional to full control over JDBC batch Ebean provides the ability on a transaction to:
- Register transaction callbacks (Post commit callback etc)
- Set and get user defined objects
- Specify if L2 cache should be skipped for the transaction
Ebean provides access to the underlying
java.sql.Connection for performing
raw JDBC if needed along with
transaction.addModification(table, ...) method to
tell Ebean what tables were modified for L2 cache invalidation.
Ebean also has built in
CallableSql for easy SQL bulk
statements and calling stored procedures.
Transaction Isolation level
Ebean lets you start a transaction at a higher Isolation level. JPA does not support this.
Ebean allows us to populate a bean (or object graph) and
update() without loading
the object object. This is useful in Rest like API's where we want to populate an entity object graph
from JSON and perform an update.
Ebean has built in
findCount which takes a copy of the query and optimises it for executing
a count (by removing fetch, ordering etc). In JPA we would use the
count() function and can't
use the same query to for a
findList type query.
JPA has no support for a
PagedList query that supports finding the "total count" for the
query as well as a page of results. (Spring Data JPA helps fill this gap somewhat).
JPA has no support for executing large queries. Ebean has
for executing large queries (cursors / streaming) that takes into account the scope of the persistence context
, JDBC driver fetchSize and MySql specific treatment (because MySql has specific issues to deal with).
JPA has no equivalent to Ebean's
findMap which returns the objects mapped by a property.
Ebean has built in support for executing queries in the background returning
findFutureList(), findFutureCount() and findFutureIds().
This provides an easy way to execute queries that can be cancelled.
Internally findFutureCount() is used as part of
PagedList query such that the
total count query can be executed in parallel to the findList() query.
As of history query
JPA has no support for SQL2011
AS OF queries yet.
Versions between history query
JPA has no support for SQL2011
VERSIONS BETWEEN queries yet.
JPA missed using generics with it's initial API and hence has both
which is not ideal.
In it's current state
JPQL is a poor language for optimising ORM queries. JPA 2.1 added
in support for
fetch groups as a query hint but there are a number of issues with this:
being rather inelegant to use, only a query hint with relatively poor support and ultimately missing
some important features for controlling object graph construction from mixed sources (L2, L3 and DB).
In JPA the emphasis on annotations
and limitations in JPQL has put JPA in a bad position for optimising ORM queries and it will be
interesting if they can get to the level of control over object graph construction that Ebean supports.
Type safe queries
You could argue there is a bit more "ceremony" with JPA Criteria queries which makes the query more verbose and harder to read.
Ebean "Query beans"
LocalDate today = new LocalDate(); List<Customer> customers = new QCustomer() .birthday.equalTo(today) .createdAt.before(today.minusYears(2)) .findList();
LocalDate today = new LocalDate(); EntityManager em = ...; CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<Customer> query = builder.createQuery(Customer.class); Root<Customer> root = query.from(Customer.class); Predicate hasBirthday = builder.equal(root.get(Customer_.birthday), today); Predicate isLongTermCustomer = builder.lessThan(root.get(Customer_.createdAt), today.minusYears(2); query.where(builder.and(hasBirthday, isLongTermCustomer)); List<Customer> customers = em.createQuery(query.select(root)).getResultList();
Java annotation processing is used by both Ebean (to generate "Query beans") and JPA (to generate JPA Query Meta model classes in order to provide type safe query construction and execution.
I suspect many JPA users look to use QueryDSL as a preference over the standard JPA Criteria meta model objects.
Unlike JPA Ebean does not require a default constructor.
Ebean has built in support for entities based on database views.
Entities without @Id
Ebean does not require entities to have an @Id property. These entities are considered "read only" and automatically bypass the persistence context. This entities are typically used for reporting purposes.
The JPA spec naming convention includes both mixed case and underscores - it is odd. Ebean's default naming
UnderscoreNamingConvention matches Hibernates
and not the JPA spec naming convention.
Auditing & @History
Ebean has built in support for
@WhoModified and full SQL2011 @History support.
JSON in DB
Ebean includes mapping support for Postgres JSONB, JSON and similar types for Oracle, MySql (and shortly SQL Server).
Ebean includes mapping support for Postgres ARRAY type.
Ebean includes support for
@SoftDelete with associated
delete permanent, cascading behavior and query support.
Ebean includes support for
@Draftable which provides
"live" and "editing" capability with