Thursday, December 27, 2012

Hibernate setMaxResults on join tables


The problem:
Let’s say I have a class: Author that has children of multiple books. I would like to retrieve the authors and books, but only want to retrieve the first 10 authors.
The hibernate api for this is to use the setMaxResults function.
The naïve thought would be that if I set the setMaxResults to 10, I will get 10 authors, but this is not true. Since all hibernate commands in the end are sql statements, what the setMaxResults does is to add a LIMIT/TOP (depending on the database) to the sql statement. What then happens is if you have a join in your query like we do, you will not get 10 authors, but actually you will get 10 books (maybe only 5 authors).

Solution, Option One:
The simple solution for this is to create two sql statements. One that will retrieve the first 10 authors id’s according to the criteria you want (including on the books). Then add the id’s to a basic search and fetch the books with the authors.

Solution, Option Two:
If you need to create the join and fetch already in the query stage, but you only want to retrieve the first 10 records that have unique authors. The next solution I propose for this is to use a cursor. Using a standard query will return all records from the db to the application. Using a cursor you can iterate over the records without bringing them all to the client. Cursors lock the db for more time, but give the option to iterate over the records without retrieving them all. To do this you call .scroll() on the query object or criteria and get a ScrollableResults object. If you are only iterating of the list use the ScrollMode.FORWARD_ONLY option to use less memory and speed the process.
Note: you need to make sure that your database supports this, since some databases like mysql fake it and bring the whole data to the client (http://stackoverflow.com/questions/2826319/using-hibernates-scrollableresults-to-slowly-read-90-million-records)

Pagination:
Some queries use a pagination scheme to get data. The standard way is to call setFirstResult.
In the first solution, you need to add the setFirstResult to the query on the id’s, and not the query with the fetch.
In the second solution this won’t work since we are back to the problem that we are counting the rows by ourselves so the setFirstResult won’t work either in hibernate query or scroll.

Dialect solution:
Currently solutions to this issue is on the dialect of the specific database. For example sql server has a row count feature where you can define the field that the sql will add the row count field (a column that has an integer of count according to another field- http://msdn.microsoft.com/en-us/library/ms186734.aspx). Then on this field you can use the standard hibernate setMaxResults and setFirstResult.



Wednesday, July 4, 2012

Java Hibernate & Proxy


One of the strenghts of  Hibernate is the option for lazy loading. This means that we do not actually load the object from the db, but hibernate creates a proxy object, and only when we actually need the object does it go to the database and get the information.
This helps on performance of the product, but can cause a lot of side effects.
The proxy class is not the actual class, but implemenets all the public methods of the real class and then delegates them to the real class when created.
Some times this is not good enought and you need the actual class and not the proxy.
After searching the internet i have found the following way to get from hibernate the actuall class and not the proxy.

public static <T> T initializeAndUnproxy(T entity) {
    if (entity == null) {
        throw new 
           NullPointerException("Entity passed for initialization is null");
    }

    Hibernate.initialize(entity);
    if (entity instanceof HibernateProxy) {
        entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()
                .getImplementation();
    }
    return entity;
}



Wednesday, June 20, 2012

Wait for JVM Garbage Collector

We all know the need to accasinally run the garbage collector.

The JVM by design does not allow you to force the garbage collector to run.

Using functions like System.gc(); or Runtime.getRuntime().gc(); only suggest to the JVM that you want to run the garbage collector.



I found a way on the internet not to force the grabage collector but to wait until the garbage collector runs.

The idea is to use the WeakReference object. This object holds a pointer to the object, but is not counted as a pointer by the garbage collector. You then release the actual pointer but continue to check the object via the WeakReference pointer until it is null.



/**
    * This method guarantees that garbage collection is
    * done unlike <code>{@link System#gc()}</code>
    */
   public static void gc() {
     Object obj = new Object();
     WeakReference ref = new WeakReference<Object>(obj);
     obj = null;
     while(ref.get() != null) {
       System.gc();
     }
   }
 
  For more information please see: http://jlibs.googlecode.com/svn/trunk/core/src/main/java/jlibs/core/lang/RuntimeUtil.java

Thursday, February 23, 2012

ubuntu ssl vpn

I don't know how many people use a ssl vpn to connect to work over ubuntu.
All i can say is that it is not fun.
The latest version of ubuntu has removed java from its repository, and this has caused a lot of problems.

After working at it for a few hours i managed to fix it, i hope my experience will help others.

First step, check how may versions of java you have on your machine:
update-java-alternatives -l

If you have more that one row, you are not in a good state.
(if for some reason you need more than one version you can use the following command to choose the default:
sudo update-alternatives --config java)

I have three rows. So the first thing i did was to remove as much as possible.
Try some of the following statements to see if it removes your versions:
sudo apt-get remove openjdk-6-jre default-jre default-jre-headless
sudo apt-get remove sun-java6-jre sun-java6-plugin sun-java6-fonts

if this does not work try using the synaptic package manager to remove all java components.
Once this is finished, you want to reinstall one version only:
sudo apt-get install sun-java6-jre sun-java6-plugin sun-java6-fonts

if you are using maven or other development tools don't forget:
sudo apt-get install sun-java6-jdk

if you need to remove the openjdk:
sudo apt-get purge openjdk-\* icedtea-\* icedtea6-\*

I have just reinstalled my machine to 11.10 and all the comments above did not work, what needs to be done is to download the script from the server site and run it from the command line, and then all is fine.

if you have a problem installing the java on 12.04 see:
https://github.com/flexiondotorg/oab-java6

also see
https://help.ubuntu.com/community/Java



So it still does not work.
How to debug:

from the command line write:
snx


based on the errors that you find search google for the solution.

Common errors:
snx: error while loading shared libraries: libpam.so.0: cannot open shared object file: No such file or directory
solution: sudo apt-get install libpam0g:i386

For more information see
 
http://kenfallon.com/check-point-ssl-network-extender/


Chaim Turkel