Native Sql Queries and the Hibernate cache

Have you ever wondered why the second level cache, after a load of thousands of cached entities, is still empty – even when the log file states that there were a lot of cache misses and puts? One reason could be that you are executing native queries through the Hibernate API without specifying the affected query space. Hibernate in this case clears the whole cache.

Our custom transaction manager used to clean the database context after every transaction. One of our developers had a good idea, he changed it to use the Hibernate API and native queries instead of plain (evil) JDBC. Now the new code looked as follow:

session.createSQLQuery("DBMS_SESSION.CLEAR_ALL_CONTEXT('application')").executeUpdate();

The problem: Hibernate now cleared the whole second level cache before closing the transaction, to keep the cache in a consistent state. We had a vast performance degradation.

If you still want to use the Hibernate API you can restrict the area that needs to be evicted (three different ways):

SQLQuery query = session.createSQLQuery("Update v_address set street='xyz'");
query.addSynchronizedEntityClass(Address.class);
query.addSynchronizedEntityName("x.y.Address");
query.addSynchronizedQuerySpace("v_address");
int updatedEntities = query.executeUpdate();

Constant variable inlining

Two days ago we discussed the impact of removing or changing a constant (i.e. public static final variable) from a Java class within an API. Most of the developers knew, that at least some of the constants were inlined into the bytecode at compile time. Some senior ones even stated, that removing the exported constant will not have an impact on the running system. Let’s have a look what the Java language specification defines and how it is really working.

References to fields that are constant variables (§4.12.4) are resolved at compile-time to the constant value that is denoted. No reference to such a field should be present in the code in a binary file (except in the class or interface containing the field, which will have code to initialize it). [JSL 13.1]

Constant variables are defined as variable of primitive type or type String that are final and initialized with a compile-time constant expression [JSL 4.12.4]. Whether an expression is compile-time constant or not is defined on two pages under [JLS 15.28]. Basically it is if composed only of operators like +, -, ~, !, <<, >>, <, <=, >, >=, == !=, etc.

Lets see the result of this definition in an example. The following class defines a few constants:

public class Constants {
	public static final int A = 32767; //int constant (inlined as sipush)
	public static final int B = 32768; //int constant (inlined as ldc)
	public static final String C = "Hello " + "World"; //String constant with operators (inlined)

	public static final Class<?> D = String.class; //Class constant (not inlined)
	public enum Direction{
		NORTH, EAST, WEST, SOUTH; //Enum constant (not inlined)
	}
}

This constants were referenced by the following client code:

public class Client {
	public static void main(String[] args) {
		int a = Constants.A;
		int b = Constants.B;
		String c = Constants.C;
		Class<?> d = Constants.D;
		Constants.Direction direction = Constants.Direction.SOUTH;
	}
}

Within the bytecode  (javap -p -v Client) we can determine the following things:

  • Integer constants with a value between -32768 and 32767 will not result in an entry in the constant pool. Instead sipush is used for better performance (see line 1).
  • Integer constants with a value outside of this scope result in an entry in the constant pool and were loaded with the command ldc (see line 3).
  • String constants also result in an entry in the constant pool and were loaded using ldc (line 5).
  • The constant referencing a class object is not a compile-time expression and therefore the value is loaded at runtime using getstatic (line 7).
  • The same for enums, because enums are normal public static final variables of no compile-time constant, they are not inlined into the client classes constant pool (line 9).
   0:	sipush	32767
   3:	istore_1
   4:	ldc	#16; //int 32768
   6:	istore_2
   7:	ldc	#17; //String Hello World
   9:	astore_3
   10:	getstatic	#19; //Field Constants.D:Ljava/lang/Class;
   13:	astore	4
   15:	getstatic	#25; //Field Constants$Direction.SOUTH:LConstants$Direction;
   18:	astore	5
   20:	return