Dariusz on Software

Methods and Tools

About This Site

Software development stuff

Archive

Entries tagged "hibernate".

Mon, 21 Sep 2009 12:46:20 +0000

I got the following error:

ORA-00932: inconsistent datatypes: expected NUMBER got BINARY

on line:

<property name="customer" column="CustomerId" />

the fix for above error was to use many-to-many tag instead of plain <property>:

<many-to-one name="customer" column="CustomerId" />

Note that class is not required here - it's computed from return type of getCustomer() getter by reflection.

hibernate_logo_a

Tags: hibernate, sql.
Mon, 09 Nov 2009 11:00:15 +0000

The error

org.hibernate.PropertyAccessException: exception setting property value with CGLIB (set hibernate.cglib.use_reflection_optimizer=false for more info) setter of XYZ.setStatus().

Cause

Using primitive types (long) where NULL is possible or using wrong type (i.e. String if "char" is declared in HBM file).

Resolution

Change from primitive type (long) to wrappers (Long) or ensure correct type is defined in mapping files.

hibernate_logo_a

Tags: hibernate.
Wed, 24 Mar 2010 14:31:27 +0000

I bet everyone knows how to enable SQL logging for Hibernate. If you add this parametr to Hibernate configuration:

<property name="hibernate.show_sql">true</property>

you will see queries like this in log file:

select roles0_.EntityKey as Entity9_1_, roles0_.ENTITYKEY as ENTITY9_168_0_
from USERROLE roles0_
where roles0_.EntityKey=?

but wait: what value is passed as parameter by Hibernate? (parameters are marked as "?" in JDBC) You have configure TRACE level for some log categories, here's example for simplelog.properties:

org.apache.commons.logging.simplelog.log.org.hibernate.SQL=trace
org.apache.commons.logging.simplelog.log.org.hibernate.engine.query=trace
org.apache.commons.logging.simplelog.log.org.hibernate.type=trace
org.apache.commons.logging.simplelog.log.org.hibernate.jdbc=trace

For your convenience here's log4j configuration:

log4j.logger.org.hibernate.SQL=trace
log4j.logger.org.hibernate.engine.query=trace
log4j.logger.org.hibernate.type=trace
log4j.logger.org.hibernate.jdbc=trace

Then you will see all passed parameters and results in logs:

[DEBUG] (generated SQL here with parameter placeholders)
[TRACE] preparing statement
[TRACE] binding '1002' to parameter: 1
[TRACE] binding '1002' to parameter: 2
[TRACE] binding '1002' to parameter: 3
[DEBUG] about to open ResultSet (open ResultSets: 0, globally: 0)
[DEBUG] about to close ResultSet (open ResultSets: 1, globally: 1)
[DEBUG] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
[TRACE] closing statement

Nothing hidden here. Happy debugging!

Tags: hibernate, java, sql.
Wed, 14 Apr 2010 08:51:24 +0000

Second level cache in Hibernate allows to greatly speed-up your application by minimizing number of SQL queries issued and serving some results from in-memory cache (with optional disk storage or distributed cache). You have option to plug in different cache libraries (or to Bring Your Own Cache - an approach popular among my colleagues from India ;-) ). There are caching limits you must be aware of when implementing 2nd level cache.

ID-based entity lookup cache

Caching entity-based lookup by id is very straightforward:

<session-factory>
    <property name="cache.provider_class">
        com.opensymphony.oscache.hibernate.OSCacheProvider
    </property>
    (...)
</session-factory>

<class name="EntityClass" table="ENTITY_TABLE">
   <cache usage="read-only" />
   (...)
</class>

Since then selecting EntityClass by id will use cache (BTW. remember to set cache expiration policy if entity is mutable!). But querying but other entity attributes will not cache the results.

Query cache

Here so-called "query cache" jumps in:

<session-factory>
    <property name="cache.use_query_cache">true</property>
    (...)
</session-factory>

Query query = new Query(EntityClass.class);
(...)
query.setCacheable(true);
query.list();

and voila! Queries issued (with parameters) are indices for cached results. The very important note is the value stored in cache. Entity keys and types are stored. Why is it important? Because it complicates caching SQL queries.

Caching SQL queries

Query cache requires query result to be Hibernate-known entity because the reason I mentioned above. That disallow to cache the following construct:

<!-- Map the resultset on a map. -->
<class name="com.comapny.MapDTO" entity-name="EntityMap">
<id name="entityKey" type="java.math.BigDecimal" column="ID" length="38"
access="com.company.MapPropertyAccessor" />
<property name="achLimit" type="java.lang.String" length="256" access="com.company.MapPropertyAccessor" />
</class>

<!-- alias is used in query -->
<resultset name="EntityMapList">
<return alias="list" entity-name="EntityMap" />
</resultset>

<sql-query name="NamedQueryName" resultset-ref="EntityMapList">
SELECT (...) AS {list.entityKey}
(...)
FROM TABLE_NAME
WHERE
(...)
</sql-query>

We will get the error:

Error: could not load an entity: EntityMap#1028
ORA-00942: table or view does not exist

EntityMap cannot be loaded separately by Hibernate because it's a DTO (data transfer object), not the entity. How to fix this error? Just change result of named query from DTO to corresponding entity. Then entity retrieved will be cached properly by Hibernate.

Tags: hibernate, java.
Thu, 29 Apr 2010 20:27:48 +0000

Recently I was asked to integrate WXS (Websphere Extreme Scale, commercial cache implementation from IBM) into existing WPS (Websphere Process Server)-based project to implement read-only non-distributed cache (one independent cache instance per JVM). The idea is to plug cache implementation using 2nd level cache interfaces defined by Hibernate.

I plugged in the objectgrid.jar into hibernate configuration:

<property name="cache.provider_class">
com.ibm.websphere.objectgrid.hibernate.cache.ObjectGridHibernateCacheProvider
</property>

then saw the following exception during Hibernate initialisation:

[4/29/10 10:08:34:462 CEST] 00000069 RegisteredSyn E WTRN0074E:
Exception caught from after_completion synchronization operation:
java.lang.NoSuchMethodError:
org/hibernate/cache/CacheException.<init>(Ljava/lang/Throwable; )V
at com.ibm.ws.objectgrid.hibernate.cache.ObjectGridHibernateCache.getSession(
ObjectGridHibernateCache.java:149)
at com.ibm.ws.objectgrid.hibernate.cache.ObjectGridHibernateCache.put(
ObjectGridHibernateCache.java:385)
at org.hibernate.cache.UpdateTimestampsCache.invalidate(
UpdateTimestampsCache.java:67)

WXS expects CacheException(java.lang.Throwable) constructor, Hibernate API supports this constructor since version 3.2. Version 3.1 currently used in project doesn't support this constructor (only CacheException(java.lang.Exception) is present). This issue forced Hibernate upgrade in the project. Note that no Hibernate version requirements found on official "requirements" page (huh?).

Conclusions:

  • BIG BLUE is not a guarantee for high quality documentation
  • Closed source is harder to implement (any problems put you in waiting support queue)
  • "Big" != Good (IMHO), would you pay for read-only cache implementation $14,400.00 per PVU and deploy giant objectgrid.jar (15M) for this very purpose? Yikes!

I'm going to talk with project sponsor about better ways to spend money (my salary increase, maybe ;-) ). Seriously: free EHCache / OSCache are more than sufficient for the task. They are small and Open Source.

"Do not hire Godzilla to pull Santa's sleigh, reindeers are better for this purpose" - Bart Simpson.

Fri, 30 Apr 2010 06:27:10 +0000

Oops! Someone forgot to renew a SSL certificate :-)

Tags: hibernate, ssl.
Wed, 19 May 2010 14:47:16 +0000

Hibernate is a library that maps database tables to Java objects. Is performance problems arise it's very easy to add database caching for application using Hibernate (just few options in config file). Hibernate is shipped with EHCache, default cache implementation. It works well and is easy to setup.

Sometimes you have to use another caching library that has no direct support for Hibernate. Here the Hibernate API comes into play. I'll show you how to plug Websphere's DistributedMap into Hibernate.

First: you have to map get/put requests into desired API. org.hibernate.cache.Cache is an interface that must be subclassed for this task. This class instance is created by Hibernate for every entity that will be cached (distinguished by regionName).

public class WebsphereCacheImpl implements Cache {
    private DistributedMap map;
    private String regionName;
    public WebsphereCacheImpl(DistributedMap map, String regionName) {
        this.map = map;
        this.regionName = regionName;
    }
    public void clear() throws CacheException {
        map.clear();
    }
    public Object get(Object key) throws CacheException {
        return map.get(getMapKey(key));
    }
    public String getRegionName() {
        return regionName;
    }
    public void put(Object key, Object value) throws CacheException {
        map.put(getMapKey(key), value);
    }
    public Object read(Object key) throws CacheException {
        return map.get(getMapKey(key));
    }
    public void remove(Object key) throws CacheException {
        map.remove(getMapKey(key));
    }
    public void update(Object key, Object value) throws CacheException {
    map.put(getMapKey(key), value);
    }
    private String getMapKey(Object key) {
        return regionName + "." + key;
    }
    (...)
}

Then you have to prepare factory for such obejcts:

public class WebsphereCacheProviderImpl implements CacheProvider {

    private DistributedMap distributedMap;

    public WebsphereCacheProviderImpl() throws NamingException {
        InitialContext ic = new InitialContext();
        distributedMap = (DistributedMap) ic.lookup("services/cache/cache1");
    }
    public Cache buildCache(String regionName, Properties arg1) throws CacheException {
        return new WebsphereCacheImpl(distributedMap, regionName);
    }
    public boolean isMinimalPutsEnabledByDefault() {
        return false;
    }
    public long nextTimestamp() {
        return new Date().getTime();
    }
    public void start(Properties arg0) throws CacheException {
    }
    public void stop() {
    }
}

Then new factory class must be registered in Hibernate configuration:

<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="cache.provider_class">com.company.project.cache.WebsphereCacheProviderImpl</property>

And voila!

Tags: hibernate, java.
Fri, 25 Jun 2010 10:38:11 +0000

Recently I've got the following error during SQL named query execution:

SQL Error: 17006, SQLState: null Invalid column name

In order to track the problem down I enabled SQL logging and collected SQL query issued, then run it under SQL monitor and ... it was working without error! I was surprised.

In order to debug what's going on I enabled detailed logging in Hibernate. What was happened then?

[INFO] could not read column value from result set: entityKey215_0_; Invalid column name

This message showed me that the problem was not related to generated SQL query but to column names expected by Hibernate. Generated recordset didn't has entityKey215_0_ column. I added:

entityKey AS {list.entityKey}

to named SQL query and error dissapeared.

This error is not-very-obvious kind of error because Oracle hides column / table names in error messages returned. Why? I don't get this cryptic error messages idea. In order to track an error under Oracle I had to enable verbose logging (error message standalone din't give anything useful). Much simpler database MySQL has better error reporting than "fat" Oracle.

Tags: hibernate, sql.

RSS feed

Tags

Created by Chronicle v3.5