This section discusses restrictions and performance optimizations that pertain to using CMP.
The following topics are addressed here:
EJB QL as defined in the EJB 2.1 Specification defines certain restrictions for the SELECT clause of an ORDER BY query (see section 11.2.8 ORDER BY Clause). This ensures that a query does not order by a field that is not returned by the query. By default, the EJB QL compiler checks the above restriction and throws an exception if the query does not conform.
However, some databases support SQL statements with an ORDER BY column that is not included in the SELECT clause. To disable the validation of the ORDER BY clause against the SELECT clause, set the DISABLE_ORDERBY_VALIDATION JVM option as follows:
asadmin create-jvm-options -Dcom.sun.jdo.spi.persistence.support.ejb.ejbqlc.DISABLE_ORDERBY_VALIDATION=true
The DISABLE_ORDERBY_VALIDATION option is set to false by default. Setting it to true results in a non-portable module or application.
On DB2, the database configuration parameter APPLHEAPSZ determines the heap size. If you are using the Oracle or DataDirect database driver, set this parameter to at least 2048 for CMP. For more information, see http://publib.boulder.ibm.com/infocenter/db2luw/v8/index.jsp?topic=/com.ibm.db2.udb.doc/opt/tsbp2024.htm.
By default, the EJB container loads the state for all persistent fields (excluding relationship, BLOB, and CLOB fields) before invoking the ejbLoad method of the abstract bean. This approach might not be optimal for entity objects with large state if most business methods require access to only parts of the state.
Use the fetched-with element in sun-cmp-mappings.xml for fields that are used infrequently. See fetched-with in Oracle GlassFish Server 3.1 Application Deployment Guide.
The following restrictions apply to the remote interface of an EJB 2.1 bean that uses CMP:
Do not expose the get and set methods for CMR fields or the persistence collection classes that are used in container-managed relationships through the remote interface of the bean.
However, you are free to expose the get and set methods that correspond to the CMP fields of the entity bean through the bean’s remote interface.
Do not expose the container-managed collection classes that are used for relationships through the remote interface of the bean.
Do not expose local interface types or local home interface types through the remote interface or remote home interface of the bean.
Dependent value classes can be exposed in the remote interface or remote home interface, and can be included in the client EJB JAR file.
Case-sensitive behavior cannot be achieved for PostgreSQL databases. PostgreSQL databases internally convert all names to lower case, which makes the following workarounds necessary:
In the CMP 2.1 runtime, PostgreSQL table and column names are not quoted, which makes these names case insensitive.
Before running the capture-schema command on a PostgreSQL database, make sure table and column names are lower case in the sun-cmp-mappings.xml file.
For EJB 2.1 beans, the lock-when-loaded consistency level is implemented by placing update locks on the data corresponding to a bean when the data is loaded from the database. There is no suitable mechanism available on Sybase databases to implement this feature. Therefore, the lock-when-loaded consistency level is not supported on Sybase databases. See consistency in Oracle GlassFish Server 3.1 Application Deployment Guide.
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.
If a field type is a Java date or time type (java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp), make sure that the field value exactly matches the value in the database.
For example, the following code uses a java.sql.Date type as a primary key field:
java.sql.Date myDate = new java.sql.Date(System.currentTimeMillis()) BeanA.create(myDate, ...);
For some databases, this code results in only the year, month, and date portion of the field value being stored in the database. Later if the client tries to find this bean by primary key as follows, the bean is not found in the database because the value does not match the one that is stored in the database.
myBean = BeanA.findByPrimaryKey(myDate);
Similar problems can happen if the database truncates the timestamp value while storing it, or if a custom query has a date or time value comparison in its WHERE clause.
For automatic mapping to an Oracle database, fields of type java.util.Date, java.sql.Date, and java.sql.Time are mapped to Oracle’s DATE data type. Fields of type java.sql.Timestamp are mapped to Oracle’s TIMESTAMP(9) data type.
For version consistency triggers on MSSQL, the property RECURSIVE_TRIGGERS must be set to false, which is the default. If set to true, triggers throw a java.sql.SQLException.
Set this property as follows:
EXEC sp_dboption 'database-name', 'recursive triggers', 'FALSE' go
You can test this property as follows:
SELECT DATABASEPROPERTYEX('database-name', 'IsRecursiveTriggersEnabled') go
The following restrictions apply when you use a MySQL database with the GlassFish Server for persistence.
MySQL treats int1 and int2 as reserved words. If you want to define int1 and int2 as fields in your table, use `int1` and `int2` field names in your SQL file.
When VARCHAR fields get truncated, a warning is displayed instead of an error. To get an error message, start the MySQL database in strict SQL mode.
The order of fields in a foreign key index must match the order in the explicitly created index on the primary table.
The CREATE TABLE syntax in the SQL file must end with the following line.
InnoDB provides MySQL with a transaction-safe (ACID compliant) storage engine having commit, rollback, and crash recovery capabilities.
For a FLOAT type field, the correct precision must be defined. By default, MySQL uses four bytes to store a FLOAT type that does not have an explicit precision definition. For example, this causes a number such as 12345.67890123 to be rounded off to 12345.7 during an INSERT. To prevent this, specify FLOAT(10,2) in the DDL file, which forces the database to use an eight-byte double-precision column. For more information, see http://dev.mysql.com/doc/mysql/en/numeric-types.html.
To use || as the string concatenation symbol, start the MySQL server with the --sql-mode="PIPES_AS_CONCAT" option. For more information, see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html and http://dev.mysql.com/doc/mysql/en/ansi-mode.html.
MySQL always starts a new connection when autoCommit==true is set. This ensures that each SQL statement forms a single transaction on its own. If you try to rollback or commit an SQL statement, you get an error message.
javax.transaction.SystemException: java.sql.SQLException: Can't call rollback when autocommit=true
javax.transaction.SystemException: java.sql.SQLException: Error open transaction is not closed
To resolve this issue, add relaxAutoCommit=true to the JDBC URL. For more information, see http://forums.mysql.com/read.php?39,31326,31404.
Change the trigger create format from the following:
CREATE TRIGGER T_UNKNOWNPKVC1 BEFORE UPDATE ON UNKNOWNPKVC1 FOR EACH ROW WHEN (NEW.VERSION = OLD.VERSION) BEGIN :NEW.VERSION := :OLD.VERSION + 1; END; /
To the following:
DELIMITER | CREATE TRIGGER T_UNKNOWNPKVC1 BEFORE UPDATE ON UNKNOWNPKVC1 FOR EACH ROW WHEN (NEW.VERSION = OLD.VERSION) BEGIN :NEW.VERSION := :OLD.VERSION + 1; END | DELIMITER ;
For more information, see http://dev.mysql.com/doc/mysql/en/create-trigger.html.
MySQL does not allow a DELETE on a row that contains a reference to itself. Here is an example that illustrates the issue.
create table EMPLOYEE ( empId int NOT NULL, salary float(25,2) NULL, mgrId int NULL, PRIMARY KEY (empId), FOREIGN KEY (mgrId) REFERENCES EMPLOYEE (empId) ) ENGINE=InnoDB; insert into Employee values (1, 1234.34, 1); delete from Employee where empId = 1;
This example fails with the following error message.
ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails
To resolve this issue, change the table creation script to the following:
create table EMPLOYEE ( empId int NOT NULL, salary float(25,2) NULL, mgrId int NULL, PRIMARY KEY (empId), FOREIGN KEY (mgrId) REFERENCES EMPLOYEE (empId) ON DELETE SET NULL ) ENGINE=InnoDB; insert into Employee values (1, 1234.34, 1); delete from Employee where empId = 1;
This can be done only if the foreign key field is allowed to be null. For more information, see http://dev.mysql.com/doc/mysql/en/innodb-foreign-key-constraints.html.
When an SQL script has foreign key constraints defined, capture-schema fails to capture the table information correctly. To work around the problem, remove the constraints and then run capture-schema. Here is an example that illustrates the issue.
CREATE TABLE ADDRESSBOOKBEANTABLE (ADDRESSBOOKNAME VARCHAR(255) NOT NULL PRIMARY KEY, CONNECTEDUSERS BLOB NULL, OWNER VARCHAR(256), FK_FOR_ACCESSPRIVILEGES VARCHAR(256), CONSTRAINT FK_ACCESSPRIVILEGE FOREIGN KEY (FK_FOR_ACCESSPRIVILEGES) REFERENCES ACCESSPRIVILEGESBEANTABLE (ROOT) ) ENGINE=InnoDB;
To resolve this issue, change the table creation script to the following:
CREATE TABLE ADDRESSBOOKBEANTABLE (ADDRESSBOOKNAME VARCHAR(255) NOT NULL PRIMARY KEY, CONNECTEDUSERS BLOB NULL, OWNER VARCHAR(256), FK_FOR_ACCESSPRIVILEGES VARCHAR(256) ) ENGINE=InnoDB;