Sun GlassFish Enterprise Server v3 Prelude Developer's Guide

Chapter 6 Using the Java Persistence API

Sun GlassFish Enterprise Server support for the Java Persistence API includes all required features described in the Java Persistence Specification. Although officially part of the Enterprise JavaBeans Specification v3.0, also known as JSR 220, the Java Persistence API can also be used with non-EJB components outside the EJB container.

The Java Persistence API provides an object/relational mapping facility to Java developers for managing relational data in Java applications. For basic information about the Java Persistence API, see “Part Four: Persistence” in the Java EE 5 Tutorial.

This chapter contains Enterprise Server specific information on using the Java Persistence API in the following topics:


Note –

The default persistence provider in the Enterprise Server is based on the EclipseLink Java Persistence API implementation. All configuration options in EclipseLink are available to applications that use the Enterprise Server's default persistence provider.



Note –

For GlassFish v3 Prelude, EJB modules are not supported unless the optional EJB container add-on component is downloaded from the Update Tool. For information about the Update Tool, see the Sun GlassFish Enterprise Server v3 Prelude Installation Guide.


Specifying the Database

The Enterprise Server uses the bundled Java DB (Derby) database by default. If the transaction-type element is omitted or specified as JTA and both the jta-data-source and non-jta-data-source elements are omitted in the persistence.xml file, Java DB is used as a JTA data source. If transaction-type is specified as RESOURCE_LOCAL and both jta-data-source and non-jta-data-source are omitted, Java DB is used as a non-JTA data source.

To use a non-default database, either specify a value for the jta-data-source element, or set the transaction-type element to RESOURCE_LOCAL and specify a value for the non-jta-data-source element.

If you are using the default persistence provider, the provider attempts to automatically detect the database type based on the connection metadata. This database type is used to issue SQL statements specific to the detected database type's dialect. You can specify the optional eclipselink.target-database property to guarantee that the database type is correct. For example:

<?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence">
        <persistence-unit name ="em1">
            <jta-data-source>jdbc/MyDB2DB</jta-data-source>
            <properties>
                <property name="eclipselink.target-database" 
                    value="DB2"/>
            </properties>
        </persistence-unit>
    </persistence>

The following eclipselink.target-database property values are allowed. Supported platforms have been tested with the Enterprise Server and are found to be Java EE compatible.

//Supported platforms
JavaDB
Derby
Oracle
MySQL4
//Others available
SQLServer
DB2
Sybase
PostgreSQL
Informix
TimesTen
Attunity
HSQL
SQLAnyWhere
DBase
DB2Mainframe
Cloudscape
PointBase

For more information about the eclipselink.target-database property, see Using EclipseLink JPA Extensions for Session, Target Database and Target Application Server.

To use the Java Persistence API outside the EJB container (in Java SE mode), do not specify the jta-data-source or non-jta-data-source elements. Instead, specify the provider element and any additional properties required by the JDBC driver or the database. For example:

<?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
        <persistence-unit name ="em2">
            <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
            <class>ejb3.war.servlet.JpaBean</class>
            <properties>
                <property name="eclipselink.target-database" 
                    value="Derby"/>
                <!-- JDBC connection properties -->
                <property name="eclipselink.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
                <property name="eclipselink.jdbc.url" 
value="jdbc:derby://localhost:1527/testdb;retrieveMessagesFromServerOnGetMessage=true;create=true;"/>
                <property name="eclipselink.jdbc.user" value="APP"/>
                <property name="eclipselink.jdbc.password" value="APP"/>
            </properties>
        </persistence-unit>
    </persistence>

For more information about eclipselink properties, see Additional Database Properties.

For a list of the JDBC drivers currently supported by the Enterprise Server, see the Sun GlassFish Enterprise Server v3 Prelude Release Notes. For configurations of supported and other drivers, see Configuration Specifics for JDBC Drivers in Sun GlassFish Enterprise Server v3 Prelude Administration Guide.

To change the persistence provider, see Changing the Persistence Provider.

Additional Database Properties

If you are using the default persistence provider, you can specify in the persistence.xml file the database properties listed at How to Use EclipseLink JPA Extensions for JDBC Connection Communication.

For schema generation properties, see Generation Options. For query hints, see Query Hints.

Configuring the Cache

If you are using the default persistence provider, you can configure whether caching occurs, the type of caching, the size of the cache, and whether client sessions share the cache. Caching properties for the default persistence provider are described in detail at Using EclipseLink JPA Extensions for Entity Caching.

Setting the Logging Level

One of the default persistence provider's properties that you can set in the persistence.xml file is eclipselink.logging.level. For example, setting the logging level to FINE or higher logs all SQL statements. For details about this property, see Using EclipseLink JPA Extensions for Logging.

Using Lazy Loading

The default persistence provider treats only OneToOne, ManyToOne, OneToMany, and ManyToMany mappings specially when they are annotated as LAZY. OneToMany and ManyToMany mappings are loaded lazily by default in compliance with the Java Persistence Specification. Other mappings are always loaded eagerly.

For basic information about lazy loading, see What You May Need to Know About EclipseLink JPA Lazy Loading.

Primary Key Generation Defaults

In the descriptions of the @GeneratedValue, @SequenceGenerator, and @TableGenerator annotations in the Java Persistence Specification, certain defaults are noted as specific to the persistence provider. The default persistence provider's primary key generation defaults are listed here.

@GeneratedValue defaults are as follows:

The @SequenceGenerator annotation has one default specific to the default provider. The default sequenceName is the specified name.

@TableGenerator defaults are as follows:

Automatic Schema Generation

The automatic schema generation feature of the Enterprise Server defines database tables based on the fields or properties in entities and the relationships between the fields or properties. This insulates developers from many of the database related aspects of development, allowing them to focus on entity development. The resulting schema is usable as-is or can be given to a database administrator for tuning with respect to performance, security, and so on. This section covers the following topics:


Note –

Automatic schema generation is supported on an all-or-none basis: it expects that no tables exist in the database before it is executed. It is not intended to be used as a tool to generate extra tables or constraints.

Deployment won't fail if all tables are not created, and undeployment won't fail if not all tables are dropped. Instead, an error is written to the server log. This is done to allow you to investigate the problem and fix it manually. You should not rely on the partially created database schema to be correct for running the application.

Schema generation occurs whenever an application is loaded. For example, schema generation occurs if the Enterprise Server is restarted with the application deployed.


Annotations

The following annotations are used in automatic schema generation: @AssociationOverride, @AssociationOverrides, @AttributeOverride, @AttributeOverrides, @Column, @DiscriminatorColumn, @DiscriminatorValue, @Embedded, @EmbeddedId, @GeneratedValue, @Id, @IdClass, @JoinColumn, @JoinColumns, @JoinTable, @Lob, @ManyToMany, @ManyToOne, @OneToMany, @OneToOne, @PrimaryKeyJoinColumn, @PrimaryKeyJoinColumns, @SecondaryTable, @SecondaryTables, @SequenceGenerator, @Table, @TableGenerator, @UniqueConstraint, and @Version. For information about these annotations, see the Java Persistence Specification.

For @Column annotations, the insertable and updatable elements are not used in automatic schema generation.

For @OneToMany and @ManyToOne annotations, no ForeignKeyConstraint is created in the resulting DDL files.

Generation Options

Optional schema generation properties control the automatic creation of database tables. You can specify them in the persistence.xml file. For more information, see Using EclipseLink JPA Extensions for Schema Generation.

Query Hints

Query hints are additional, implementation-specific configuration settings. You can use hints in your queries in the following format:

setHint("hint-name", hint-value)

For example:

Customer customer = (Customer)entityMgr.
     createNamedQuery("findCustomerBySSN").
     setParameter("SSN", "123-12-1234").
     setHint("eclipselink.refresh", true).
     getSingleResult();

For more information about the query hints available with the default provider, see How to Use EclipseLink JPA Query Hints.

Changing the Persistence Provider


Note –

The previous sections in this chapter apply only to the default persistence provider. If you change the provider for a module or application, the provider-specific database properties, query hints, and schema generation features described in this chapter do not apply.


You can change the persistence provider for an application in the manner described in the Java Persistence API Specification.

First, install the provider. Copy the provider JAR files to the domain-dir/lib directory, and restart the Enterprise Server. For more information about the domain-dir/lib directory, see Using the Common Class Loader. The new persistence provider is now available to all modules and applications deployed on servers that share the same configuration. However, the default provider remains the same.

In your persistence unit, specify the provider and any properties the provider requires in the persistence.xml file. For example:

<?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence">
        <persistence-unit name ="em3">
            <provider>com.company22.persistence.PersistenceProviderImpl</provider>
            <properties>
                <property name="company22.database.name" value="MyDB"/>
            </properties>
        </persistence-unit>
    </persistence>

To migrate from Oracle TopLink to EclipseLink, see Migrating from Oracle TopLink to EclipseLink.

Restrictions and Optimizations

This section discusses restrictions and performance optimizations that affect using the Java Persistence API.

Extended Persistence Context

If a stateful session bean is passivated, its extended persistence context could be lost when the stateful session bean is activated. In this environment, it is safe to store an extended persistence context in a stateful session bean only if you can safely disable stateful session bean passivation altogether. This is possible, but trade-offs in memory utilization must be carefully examined before choosing this option.

It is safe to store a reference to an extended persistence context in an HttpSession.

Using @OrderBy with a Shared Session Cache

Setting @OrderBy on a ManyToMany or OneToMany relationship field in which a List represents the Many side doesn't work if the session cache is shared. Use one of the following workarounds:

Using BLOB or CLOB Types with the Inet Oraxo JDBC Driver

To use BLOB or CLOB data types larger than 4 KB for persistence using the Inet Oraxo JDBC Driver for Oracle Databases, you must set the database's streamstolob property value to true.

Database Case Sensitivity

Mapping references to column or table names must be in accordance with the expected column or table name case, and ensuring this is the programmer's responsibility. If column or table names are not explicitly specified for a field or entity, the Enterprise Server uses upper case column names by default, so any mapping references to the column or table names must be in upper case. If column or table names are explicitly specified, the case of all mapping references to the column or table names must be in accordance with the case used in the specified names.

The following are examples of how case sensitivity affects mapping elements that refer to columns or tables. Programmers must keep case sensitivity in mind when writing these mappings.

Unique Constraints

If column names are not explicitly specified on a field, unique constraints and foreign key mappings must be specified using uppercase references. For example:

@Table(name="Department", uniqueConstraints={ @UniqueConstraint ( columnNames= { "DEPTNAME" } ) } )

The other way to handle this is by specifying explicit column names for each field with the required case. For example:

@Table(name="Department", uniqueConstraints={ @UniqueConstraint ( columnNames= { "deptName" } ) } )
public class Department{ @Column(name="deptName") private String deptName; }

Otherwise, the ALTER TABLE statement generated by the Enterprise Server uses the incorrect case, and the creation of the unique constraint fails.

Foreign Key Mapping

Use @OneToMany(mappedBy="COMPANY") or specify an explicit column name for the Company field on the Many side of the relationship.

SQL Result Set Mapping

Use the following elements:

<sql-result-set-mapping name="SRSMName" >
   <entity-result entity-class="entities.someEntity" />
   <column-result name="UPPERCASECOLUMNNAME" />
</sql-result-set-mapping>

Or specify an explicit column name for the upperCaseColumnName field.

Named Native Queries and JDBC Queries

Column or table names specified in SQL queries must be in accordance with the expected case. For example, MySQL requires column names in the SELECT clause of JDBC queries to be uppercase, while PostgreSQL and Sybase require table names to be uppercase in all JDBC queries.

PostgreSQL Case Sensitivity

PostgreSQL stores column and table names in lower case. JDBC queries on PostgreSQL retrieve column or table names in lowercase unless the names are quoted. For example:

use aliases Select m.ID AS \"ID\" from Department m

Use the backslash as an escape character in the class file, but not in the persistence.xml file.

Sybase Finder Limitation

If a finder method with an input greater than 255 characters is executed and the primary key column is mapped to a VARCHAR column, Sybase attempts to convert type VARCHAR to type TEXT and generates the following error:

com.sybase.jdbc2.jdbc.SybSQLException: Implicit conversion from datatype 
'TEXT' to 'VARCHAR' is not allowed.  Use the CONVERT function to run this 
query.

To avoid this error, make sure the finder method input is less than 255 characters.

MySQL Database Restrictions

The following restrictions apply when you use a MySQL database with the Enterprise Server for persistence.