- JDO uses the object – relational mapping (ORM) model. This means that there is a direct mapping between JDO instances to the underlying data store
- With the ORM model usage, JDO has the capability to work with a variety of data storage mechanisms such as relational databases, object databases, file systems and XML documents
- If an application references a persistent object and alters any of its persistent state in memory, the JDO implementation will implicitly update the data store when the active transaction is committed. This relieves the applicationdeveloper of repeatedly coding explicit save operations on the database
This brings us to some of the advantages of JDO:
- Quick development mechanism and ease of usage: Application developers only need to understand and develop applications based on their domain object model. The mechanism in which each of the data values in the database tables are stored / inserted is left to the JDO implementation
- High performance: Since JDO retrieves the result set objects from the data store and caches them in memory by default, the database operations are fast and optimized. Also, since the persistence aspects of data is handled by JDOand not application programmer, the data access and write patterns are optimized by JDO for optimal performance
- Database independence: Applications written with the JDO API are independent of the underlying database. JDO implementations support many different kinds of transactional data stores, including relational and object databases, XML, flat files, and others
- Ease of integration with EJB: Applications can take advantage of EJB features such as remote message processing, automatic distributed transaction coordination, and security, using the same domain object models throughout the enterprise
- Implementation independence: Object – relation mapping makes the application highly portable with respect to implementation mechanisms. There is no need to recompile or change the source code while porting the application from one implementation mechanism to another
- Excellent model of database connectivity for pilot projects: Since JDO allows the application developer to develop applications very quickly, this becomes one of the strong reasons of choosing JDO for implementing quickpilot projects.
Data fetch mechanism by JDO:
JDO fetches data from databases in the form of simple Plain Old Java Objects (POJO) objects. This is done in such a way that for every row of data fetched, there is a POJO object retrieved with the individual values (columns) being attributes of this POJO object.
Hence, for database reads involving, say 100 rows of result set being fetched, then an array of 100 POJO objects are returned to the application which is handled through means of collection and iteration classes supported in the standard Java API libraries.
There are few things to note with the above mechanism of data fetch by JDO –
- Number of POJO objects returned is directly proportional to the number of rows returned by database read operations
- Size of a POJO object is proportional to the total size of all data contained in that row for which the POJO object is being returned
- Each of these POJO objects is stored in memory (caching) for enhancing future database read operations time. If the number of rows returned by queries are very high (say, > 5,000), and the total size of each of these rows is high (say, > 500 KB or so), then the application memory consumption grows high. (5,000 * 500 KB ~= 2.38 GB, application memory
- Another corollary to this is that, for read queries fetching all data resulting due to the query at once, if the data grows both in size and number in the database, the performance of read queries will continue to degrade over time and will also lead to exhaustion of application memory. (In case of Java, the heap memory). Hence, it is very important to understand the usage of application in terms of the database table sizes, number of rows fetched per read query so as to optimize memory consumption of the application and thus preventing application server crashes resulting due to exhaustion of application runtime memory.
Implementation best practices – prevent memory leaks:
Out of memory error:
The heap memory gets utilized as the java application workloads are executed. Java allocates objects in this data area for all object requests made by application. If an object cannot be allocated in the heap due to unavailability of enough memory for allocation, an allocation failure occurs. Every such allocation failure triggers the Garbage collection (GC) algorithm to kick in which sweeps the entire heap and reclaims objects which are no longer referenced (dead objects).
The heap may be of a fixed size, but can also be expanded when more memory is needed or contracted when no longer needed. If a larger heap is needed and it cannot be allocated, an OutOfMemory exception is thrown, resulting in application server crash generating a heapdump file consisting of details of the contents of the heap when the out of memory occurred.
Common causes of out of memory pertaining to use of JDO:
- Not enough heap - The JVM needs more memory to deal with the application requirements. Queries returning more objects than usual can be the cause.
- Memory Leaks - The application does not close the resources, like the PersistenceManager, EntityManager or Queries, and the JVM cannot reclaim the memory
- Caching: Use of unbounded caching mechanisms, strong references which do not get de-referenced throughout the length of application uptime because of which Garbage collector is unable to reclaim any object / release memory
- Memory Fragmentation - A large object needs to be placed in the memory, but the JVM cannot allocate a continuous space to it because the memory is fragmented
- JDBC driver - a bug in the JDBC driver not flushing resources or keeping large result sets in memory.
Further analysis and troubleshooting techniques with JDO is continued in the next section of this blog titled - "Troubleshooting and memory leak analysis with JDO"