EclipseLink/FAQ/JPA

From Eclipsepedia

Jump to: navigation, search

Contents

What is Object-Relational Mapping

Object-relational mapping or ORM is the category of products that provide services to map objects to relational databases. The Java Persistence API (JPA) is the Java specification that provides a standard to ORM in Java. JPA provides both a standard mapping definition (through annotations or XML) and a standard runtime API and object-level query language (JPQL). JPA is part of the EJB specification and JEE platform, but can also be used in JSE.

EclipseLink provides sophisticated and high performance object-relational mapping services and complete support for the JPA specification. JPA objects are mapped through the package javax.persistence annotations and JPA persistence.xml and orm.xml. EclipseLink also provides extended annotations through the package org.eclipse.persistence.annotations. JPA provides a runtime API through the EntityManager class in the javax.persistence package. EclipseLink also provides extended runtime API through the package org.eclipse.persistence.jpa.

EclipseLink also provides a POJO ORM API and mapping model which its JPA support is based on. The mapping model classes are in the org.eclipse.persistence.descriptors and org.eclipse.persistence.mappings packages, and sessions.xml and project.xml files. The runtime API is provided through the Session and UnitOfWork classes in the org.eclipse.persistence.sessions package.

What are the Best Practices for using EclipseLink JPA?

See EclipseLink JPA Best Practices.

What version of JPA does EclipseLink support?

EclipseLink fully supports JPA 2.0, in fact, EclipseLink is the JPA 2.0 reference implementation.

EclipseLink can also be used the Java EE servers that only support JPA 1.0.

EclipeLink 2.4 also supports some aspects of the JPA 2.1 draft.

What features beyond JPA does EclipseLink support?

EclipseLink provides additional features beyond the JPA specification.

These include:

  • Caching: shared/isolated/protected, clustered cache coordination, invalidation, indexes, in-memory querying, database events driven invalidation
  • Mapping: history, additional criteria, interfaces, variable relationships
  • JPQL: FUNC, TREAT, ON, FUNCTION, OPERATOR, SQL, TABLE, COLUMN, CAST, EXTRACT, REGEXP, FROM sub-select, SELECT sub-select, NULLS FIRST/LAST, UNION, INTERSECT, EXCEPT
  • Querying: join fetch, batch fetch, fetch groups, connect by, SQL hints, cursors, map results, expressions
  • Database: Oracle, MySQL, PostgreSQL, DB2, SQL Server, Sybase, Derby, H2, HSQL, MaxDB, Symfoware
  • Oracle: XDB, spatial, lobs, QCN/DCN, VPD, flashback, returning
  • NoSQL: MongoDB, Oracle NoSQL, XML files, JMS, Oracle AQ, JCA
  • Java EE: WebLogic, Glassfish, WebSphere, JBoss
  • OSGi, Spring

Migrating to EclipseLink JPA

How do I migrate from using Oracle TopLink to EclipseLink?

See Oracle TopLink

How do I migrate from using TopLink Essentials to EclipseLink?

See TopLink Essentials

How do I migrate from another JPA provider to EclipseLink?

See JPA Migration

What databases are supported?

EclipseLink supports any relational database that is compliant with SQL and has a compliant JDBC driver. EclipseLink has extended support for several database platforms. The extended support mainly consists of providing native sequencing support, schema creation, and certain database functions. These platform classes can be found in the org.eclipse.persistence.platform.database and org.eclipse.persistence.platform.database.oracle packages.

These include:

  • Oracle
  • Oracle JDBC (8, 9, 10, 11)
  • MySQL
  • PostgreSQL
  • Derby
  • DB2
  • DB2 (mainframe)
  • Microsoft SQL Server
  • Sybase
  • Informix
  • SQL Anywhere
  • HSQL
  • H2
  • Firebird
  • Microsoft Access
  • Attunity
  • Cloudscape
  • DBase
  • PointBase
  • TimesTen
  • Symfoware
  • MaxDB

It also possible to extend EclipseLink to add extended support for additional platforms. There are also several user contributed platforms in the EclipseLink incubator project, see Platform Incubator.

EclipseLink has extended support for Oracle JDBC drivers. Including:

  • LOB's
  • NChar's
  • XMLType's
  • TIMESTAMP (TZ, LTZ)'s
  • Native batch writing
  • Structured object-relational data-types
  • PLSQL data-types and stored procedures
  • VPD, RAC, proxy authentication
  • XDK XML parser

EclipseLink also has support for structure object-relational data-types and databases, and NoSQL and Enterprise Information Systems (EIS, legacy data-sources and messaging platforms).

See NoSQL.

Does EclipseLink support NoSQL databases?

EclipseLink supports NoSQL databases and Enterprise Information Systems (EIS, legacy data-sources and messaging platforms).

See NoSQL.

How is EclipseLink integrated with the Oracle database?

EclipseLink is completely independent from, but also tightly integrated with the Oracle database. EclipseLink has extended support for most Oracle SQL, JDBC and database extensions.

EclipseLink's extended support for the Oracle database includes:

  • LOB's
  • NChar's
  • XMLType's
  • TIMESTAMP (TZ, LTZ)'s
  • Native batch writing
  • Structured object-relational data-types
  • PLSQL data-types and stored procedures
  • VPD, RAC, proxy authentication
  • XDK XML parser
  • Hierarchical selects (Select by prior)
  • Returning clause
  • Flashback history and queries
  • Stored procedures, output parameters and output cursors
  • Stored functions
  • Oracle AQ

How to access table, column and schema information at runtime?

EclipseLink stores the mapping metadata from the JPA annotations and orm.xml in its ClassDescriptor and DatabaseMapping objects. These objects can be accessed at runtime from the EntityManager or EntityManagerFactory by casting or unwrapping to the EclipseLink JPA interface.

EntityManager em = getEntityManager();
String table = em.unwrap(JpaEntityManager.class).getServerSession().getDescriptor(MyClass.class).getTables().get(0).getName();
String schema = em.unwrap(JpaEntityManager.class).getServerSession().getDescriptor(MyClass.class).getTables().get(0).getTableQualifier();
String column = em.unwrap(JpaEntityManager.class).getServerSession().getDescriptor(MyClass.class).getMappingForAttributeName("myAttribute").getField().getName();

If you use JPA annotations, you may also be able to access specified schema information using Java reflection to access your annotation objects.

The JPA 2.0 metamodel can also be used to provide information on how the attributes are mapped (but not their database schema information).

You can also use native SQL queries to query your database catalogs for schema information, or use the JDBC connection metadata APIs. EclipseLink also exposes the JDBC catalog APIs through its SchemaManager class.

How to access the JDBC connection?

Sometimes when using JPA it may be required to have lower level access to your database through JDBC. If you are using a JEE DataSource, you can just access the same DataSource that JPA uses, if it is a JTA DataSource it will be in the same transaction context as JPA.

If you are not using a DataSource, or want the same connection in the same transaction as JPA, you can obtain the JDBC Connection from the EntityManager.

See, Getting a JDBC Connection from an EntityManager

How to disable or enable weaving?

In a Java SE environment weaving is not enabled by default. This can affect LAZY OneToOne, ManyToOne and Basic relationships. It also has a major effect on performance and disable attribute change tracking.

To enable weaving in Java SE, the EclipseLink agent must be used when starting the Java VM.

 java -javaagent:eclipselink.jar

Spring could also be used to allow JPA weaving in Java SE.

Static weaving can also be used to weave your jar.

See, How to Configure Static Weaving

In a Java EE environment weaving is enabled by default (on any JEE EJB 3.0 fully compliant app server, Weblogic, Webspehere, Glassfish. JBoss does not allow weaving so you must use static weaving or Spring).

To disable weaving the weaving persistence unit property can be used,

 <property name="eclipselink.weaving" value="false">

For more information on weaving see the EclipseLink UserGuide, Using EclipseLink JPA Weaving

Are stored procedures and triggers supported?

EclipseLink has extended support for stored procedures and triggers.

Stored procedures are support through the @NamedStoredProcedureQuery, @NamedStoredFunctionQuery, @NamedPLSQLStoredFunctionQuery, @NamedPLSQLStoredProcedureQuery, StoredProcedureCall, StoredFunctionCall, PLSQLStoredProcedureCall, and PLSQLStoredFunctionCall classes.

The following stored procedures features are supported:

  • IN parameters
  • OUT parameter
  • INOUT parameters
  • result sets
  • CURSOR OUT parameters
  • Object-relational datatypes (Struct, Array)
  • Oracle PLSQL types such as TABLE, RECORD, BOOLEAN
  • Using a stored procedure in a named query
  • Using a stored procedure in a dynamic query
  • Using a stored procedure to override an Entity's persist, update, remove or find query.
  • Using a stored procedure to override a mapping's select, insert or delete query.
  • Stored functions
  • Oracle, SQL Server, MySQL, Sybase, DB2, other stored procedure capable platforms


Triggers can be used in the tables being processed by EclipseLink.

If a trigger is updating data required back in the application, or the id, the @ReturnInsert, @ReturnUpdate or ReturningPolicy can be used the return the values updated by the trigger.

How to get the SQL for a Query?

To see the SQL for a JPA Query you can enable logging on FINE or lower.

To get the SQL for a specific Query at runtime you can use the DatabaseQuery API.

Session session = em.unwrap(JpaEntityManager).getActiveSession();
DatabaseQuery databaseQuery = ((EJBQueryImpl)query).getDatabaseQuery();
databaseQuery.prepareCall(session, new DatabaseRecord());
String sqlString = databaseQuery.getSQLString();

This SQL will contain ? for parameters. To get the SQL translated with the arguments you need a DatabaseRecord with the parameter values.

Session session = em.unwrap(JpaEntityManager).getActiveSession();
DatabaseQuery databaseQuery = ((EJBQueryImpl)query).getDatabaseQuery();
String sqlString = databaseQuery.getTranslatedSQLString(session, recordWithValues);

How to diagnose and resolve hangs and deadlocks?

A system hang, or deadlock is one of the most difficult problems to diagnose and resolve.

The first task is to determine where the application is hanging.

Use ctrl<break> on Windows or kill on Unix, or a debugger to log the stack trace to identify what the hung threads are blocked on.

Possible sources include:

  • Application - the application uses locks or synchronized methods causing the hang.
    • This should be the easiest to diagnose, as it is within your own code.
  • Database - the database is deadlocked on a set of transactions.
    • You will see JDBC access as the last call on the stack.
    • This is normally causes by database table, row and page locks.
    • Check for usages of pessimistic locking, or concurrent updates to the same set of rows.
    • EclipseLink avoids database deadlocks through several mechanisms, including providing optimistic locking, a read and sequence connection pool, and ordering writes by table, and ordering updates and deletes by id.
    • Ensure a sequence connection pool is being used if using TABLE sequencing. See PersistenceUnitProperties.CONNECTION_POOL_SEQUENCE;
    • Avoid using a SERIALIZABLE or strict database transaction isolation level.
  • Connection pool - the application has exceed the size of the connection pool and a thread with a connection requires an additional connection.
    • You will see a connection request as the last method on the stack.
    • Ensure an adequate number of connections in your connection pool.
  • Cache - If using a shared cache, EclipseLink requires locking the cache on reads and writes to ensure consistency.
    • You will see cache access, such as IdentityMapManager acquireLock or acquireDeferredLock, or WriteLockManager as the last call on the stack.
    • Ensure you are using the latest EclipseLink release, the issue may have been fixed. Otherwise log a bug including the relevant stack dump.
    • This is normally related to having relationships that do not use LAZY, ensure all relationship use LAZY.
      • An alternative to using LAZY is to set the persistence unit property, "eclipselink.weaving.eager"="true".
    • It can also be caused by join fetching, so remove any join fetches to diagnose the problem.
    • A workaround is to disable the shared cache. See How to disable the shared cache?.
    • The cache isolation in EclipseLink can be configured. Try using a SessionCustomizer to call session.getLogin().setCacheTransactionIsolation(CONCURRENT_READ_WRITE).
    • A possible workaround is to configure DeferredLockManager.SHOULD_USE_DEFERRED_LOCKS = false.

Do I have to maintain both sides of a bi-directional relationship?

Yes, you need to maintain both sides of the relationship in JPA. It is a common problem that an application does not do this, and then sees inconsistent objects afterwords. This is normally not done by mistake, but is also done on purpose, normally with a ManyToOne/OneToMany relationship, where the application programmer wants to avoid the cost of reading in the OneToMany collection, especially if it is large.

If you are updating a child in a OneToMany, then you just need to find() it, and update it, or use merge(). You do not need to merge() or modify the parent or its children relationship.

If you are adding a new child, then you need to persist() or merge() it, set its parent to the one from the current persistence context using find() (merge can do this, but if your parent is transient, or nulled out, then you need to do this yourself, and if the parent's children are transient or nulled out, then you need to be careful it is not merged or cascaded). You also need to add the child to the parent's children (otherwise it will not be there in the current persistence context, or possibly future ones if you are using a shared cache).

If you are deleting a child, then you need to call remove() on it, unless you have set the relationship to deleteOrphans. You also need to remove it from the parent's children, (otherwise it will still be there in the current persistence context, or possibly future ones if you are using a shared cache).

There are alternatives to adding and removing the child though, if you want to avoid the cost of reading the children:

  • If you are using LAZY relationship, a List (it is also possible with Set, but there can be issues), and weaving (static or dynamic), then add() and remove() will not instantiate the children.
  • If the children is not something you want to ever read, then consider not mapping it, just query it if needed.
  • If the parent's children is not instantiated, you could avoid adding the child. (see PersistenceUnitUtil.isLoaded()).
  • You can call refresh() on the parent after the commit to reset its children.
  • You can avoid adding the child if you clear or throw away your persistence unit, and are not using a shared cache.