martedì 23 novembre 2010

Hibernate tip and tricks

How can I count the number of query results without actually returning them?


Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();

How can I find the size of a collection without initializing it?


Integer size = (Integer) s.createFilter( collection, "select count(*)" ).uniqueResult();

How can I order by the size of a collection?

Use a left join, together with group by


select user 
from User user
left join user.messages msg
group by user 
order by count(msg)

How can I place a condition upon a collection size?

If your database supports subselects:

from User user where size(user.messages) >= 1

or:

from User user where exists elements(user.messages)

If not, and in the case of a one-to-many or many-to-many association:

select user 
from User user 
join user.messages msg 
group by user 
having count(msg) >= 1

Because of the inner join, this form can't be used to return a User with zero messages, so the following form is also useful

select user 
from User as user
left join user.messages as msg
group by user 
having count(msg) = 0

How can I query for entities with empty collections?


from Box box
where box.balls is empty

Or, try this:

select box
from Box box
   left join box.balls ball
where ball is null

How can I sort / order collection elements?

There are three different approaches:
  1. Use a SortedSet or SortedMap, specifying a comparator class in the sort attribute or <set> or <map>. This solution does a sort in memory.
  2. Specify an order-by attribute of <set>, <map> or <bag>, naming a list of table columns to sort by. This solution works only in JDK 1.4+.
  3. Use a filter session.createFilter( collection, "order by ...." ).list()

Are collections pageable?


Query q = s.createFilter( collection, "" ); // the trivial filter
q.setMaxResults(PAGE_SIZE);
q.setFirstResult(PAGE_SIZE * pageNumber);
List page = q.list();

I have a one-to-one association between two classes. Ensuring that associated objects have matching identifiers is bugprone. Is there a better way?


<generator class="foreign">
     <param name="property">parent</param>
</generator>

I have a many-to-many association between two tables, but the association table has some extra columns (apart from the foreign keys). What kind of mapping should I use?

Use a composite-element to model the association table. For example, given the following association table:

create table relationship ( 
    fk_of_foo bigint not null, 
    fk_of_bar bigint not null, 
    multiplicity smallint, 
    created date )

you could use this collection mapping (inside the mapping for class Foo):

<set name="relationship">
    <key column="fk_of_foo"/>
    <composite-element class="Relationship">
        <property name="multiplicity" type="short" not-null="true"/>
        <property name="created" type="date" not-null="true"/>
        <many-to-one name="bar" class="Bar" not-null="true"/>
    </composite-element>
</set>

You may also use an <idbag> with a surrogate key column for the collection table. This would allow you to have nullable columns.

An alternative approach is to simply map the association table as a normal entity class with two bidirectional one-to-many associations.

In an MVC application, how can we ensure that all proxies and lazy collections will be initialized when the view tries to access them?

One possible approach is to leave the session open (and transaction uncommitted) when forwarding to the view. The session/transaction would be closed/committed after the view is rendered in, for example, a servlet filter (another example would by to use the ModelLifetime.discard()  callback in Maverick). One difficulty with this approach is making sure the session/transaction is closed/rolled back if an exception occurs rendering the view.

Another approach is to simply force initialization of all needed objects using Hibernate.initialize(). This is often more straightforward than it sounds.Another approach is to simply force initialization of all needed objects using Hibernate.initialize(). This is often more straightforward than it sounds.

How can I bind a dynamic list of values into an in query expression?


Query q = s.createQuery("from foo in class Foo where foo.id in (:id_list)");
q.setParameterList("id_list", fooIdList);
List foos = q.list();

How can I bind properties of a JavaBean to named query parameters?


Query q = s.createQuery("from foo in class Foo where foo.name=:name and foo.size=:size");
q.setProperties(fooBean); // fooBean has getName() and getSize()
List foos = q.list();

Can I map an inner class?

You may persist any static inner class. You should specify the class name using the standard form ie. eg. Foo$Bar

How can I assign a default value to a property when the database column is null?

Use a UserType.

How can I trucate String data?

Use a UserType.

How can I trim spaces from String data persisted to a CHAR column?

Use a UserType.

How can I convert the type of a property to/from the database column type?

Use a UserType.

How can I get access to O/R mapping information such as table and column names at runtime?

This information is available via the Configuration object. For example, entity mappings may be obtained using Configuration.getClassMapping(). It is even possible to manipulate this metamodel at runtime and then build a new SessionFactory.

How can I create an association to an entity without fetching that entity from the database (if I know the identifier)?

If the entity is proxyable (lazy="true"), simply use load(). The following code does not result in any SELECT statement:

Item itemProxy = (Item) session.load(Item.class, itemId);
Bid bid = new Bid(user, amount, itemProxy);
session.save(bid);

How can I retrieve the identifier of an associated object, without fetching the association?

Just do it. The following code does not result in any SELECT statement, even if the item association is lazy.

Long itemId = bid.getItem().getId();
 

This works if getItem() returns a proxy and if you mapped the identifier property with regular accessor methods. If you enabled direct field access for the id of an Item, the Item proxy will be initialized if you call getId(). This method is then treated like any other business method of the proxy, initialization is required if it is called.

How can I manipulate mappings at runtime?

You can access (and modify) the Hibernate metamodel via the Configuration object, using getClassMapping(), getCollectionMapping(), etc.

Note that the SessionFactory is immutable and does not retain any reference to the Configuration instance, so you must re-build it if you wish to activate the modified mappings.

How can I avoid n+1 SQL SELECT queries when running a Hibernate query?

Follow the best practices guide! Ensure that all <class> and <collection> mappings specify lazy="true" in Hibernate2 (this is the new default in Hibernate3). Use HQL LEFT JOIN FETCH to specify which associations you need to be retrieved in the initial SQL SELECT.

A second way to avoid the n+1 selects problem is to use fetch="subselect" in Hibernate3.

If you are still unsure, refer to the Hibernate documentation and Hibernate in Action.

I have a collection with second-level cache enabled, and Hibernate retrieves the collection elements one at a time with a SQL query per element!

Enable second-level cache for the associated entity class. Don't cache collections of uncached entity types.

How can I insert XML data into Oracle using the xmltype() function?

Specify custom SQL INSERT (and UPDATE) statements using <sql-insert> and <sql-update> in Hibernate3, or using a custom persister in Hibernate 2.1.

You will also need to write a UserType to perform binding to/from the PreparedStatement.

How can I execute arbitrary SQL using Hibernate?


PreparedStatement ps = session.connection().prepareStatement(sqlString);

Or, if you wish to retrieve managed entity objects, use session.createSQLQuery().

Or, in Hibernate3, override generated SQL using <sql-insert>, <sql-update>, <sql-delete> and <loader> in the mapping document.

I want to call an SQL function from HQL, but the HQL parser does not recognize it!

Subclass your Dialect, and call registerFunction() from the constructor.

Hibernate performance faqs

How does Hibernate perform?

We claim that Hibernate performs well, in the sense that its performance is limited by the underlying JDBC driver / relational database combination. Given this, the question boils down to: does Hibernate implement its functionality using a minimal number of database queries and how can it improve performance and scalability on top of JDBC? This page hopefully answers these questions.

But Hibernate uses so much runtime reflection?

Many former C or C++ programmers prefer generated-code solutions to runtime reflection. This is usually justified by reference to the performance red-herring. However, modern JVMs implement reflection extremely efficiently and the overhead is minimal compared to the cost of disk access or IPC. Developers from other traditions (eg. Smalltalk) have always relied upon reflection to do things that C/C++ needs code-generation for.

In the very latest versions of Hibernate, "reflection" is optimised via the CGLIB runtime bytecode generation library. This means that "reflected" property get / set calls no longer carry the overhead of the Java reflection API and are actually just normal method calls. This results in a (very) small performance gain.

Okay, so what are the advantages of reflection then?

A quicker compile-build-test cycle. The advantage of this should not be understated. The philosophy of Hibernate is this: let the developer spend as little time as possible implementing persistence for the 95% of the application which is used 5% of the time. Then, later, if there are performance issues with the remaining 5%, there will be plenty of time left for hand-coding JDBC calls to improve performance of particular bottlenecks. (Most of the time Hibernate very closely approaches the performance of hand-coded JDBC anyway.)

But how does it scale?

Hibernate implements an extremely high-concurrency architecture with no resource-contention issues (apart from the obvious - contention for access to the database). This architecture scales extremely well as concurrency increases in a cluster or on a single machine.

A more difficult question is how efficiently Hibernate utilizes memory under heavy load.

Since there is no sharing of objects between concurrent threads (like EJB 2.x entity beans), and since Hibernate does not automatically do instance-pooling (unlike EJB 2.x entity beans), you might think that memory utilization would be less efficient, and this may be true to an extent. However, our experience with real Java applications is that the benefits of instance-pooling are almost negated by common Java coding style. Very often programmers create a new HashMap in ejbLoad ..... or return a new Integer from a method call .... or do some string manipulations. Furthermore, every time you load and then passivate a bean, every non-primitive field of the bean is garbage, not to mention whatever garbage the JDBC driver leaves behind. All these kinds of operations leave behind as much garbage as we avoided by doing instance-pooling.

Please note that Hibernate is not a competitor to EJB. In fact,  Hibernate EntityManager and Annotations implement a persistence service  for EJB 3.0 entity beans, on top of the Hibernate Core architecture.

All this leads to Hibernate not needing a locking or synchronization mechanism, in memory, or to a lock table on disk. As stated earlier, Hibernate completely relies on the database management systems ability to deal with concurrent access; the experience of the DBMS vendors in this area should be used.

The other side of scalability is downward scalability. While it wasn't designed with small devices in mind, Hibernate nevertheless has a small footprint and could be used on machines with much less memory than you would need to run an application server. If it can run a JVM and a database, it should be able to run Hibernate.

Why not implement instance-pooling anyway?

Firstly, it would be pointless. There is a lower bound to the amount of garbage Hibernate creates every time it loads or updates and object - the garbage created by getting or setting the object's properties using reflection.

More importantly, the disadvantage of instance-pooling is developers who forget to reinitialize fields each time an instance is reused. We have seen very subtle bugs in EJBs that don't reinitialize all fields in ejbCreate.

On the other hand, if there is a particular application object that is extremely expensive to create, you can easily implement your own instance pool for that class and use the version of Session.load() that takes a class instance. Just remember to return the objects to the pool every time you close the session.

Does Hibernate implement its functionality using a minimal number of database queries?

Good Question. Hibernate can make certain optimizations all the time:
  • Caching objects. The session is a transaction-level cache of persistent objects. You may also enable a JVM-level/cluster cache to memory and/or local disk.
  • Executing SQL statements later, when needed. The session never issues an INSERT or UPDATE until it is actually needed. So if an exception occurs and you need to abort the transaction, some statements will never actually be issued. Furthermore, this keeps lock times in the database as short as possible (from the late UPDATE to the transaction end).
  • Never updating unmodified objects. It is very common in hand-coded JDBC to see the persistent state of an object updated, just in case it changed.....for example, the user pressed the save button but may not have edited any fields. Hibernate always knows if an object's state actually changed, as long as you are inside the same (possibly very long) unit of work.
  • Efficient Collection Handling. Likewise, Hibernate only ever inserts/updates/deletes collection rows that actually changed.
  • Rolling two updates into one. As a corollary to (1) and (3), Hibernate can roll two seemingly unrelated updates of the same object into one UPDATE statement.
  • Updating only the modified columns. Hibernate knows exactly which columns need updating and, if you choose, will update only those columns.
  • Outer join fetching. Hibernate implements a very efficient outer-join fetching algorithm! In addition, you can use subselect and batch pre-fetch optimizations.
  • Lazy collection initialization.
  • Lazy object initialization. Hibernate can use runtime-generated proxies (CGLIB) or interception injected through bytecode instrumentation at build-time.

A few more (optional) features of Hibernate that your handcoded JDBC may or may not currently benefit from
  • second-level caching of arbitrary query results, from HQL, Criteria, and even native SQL queries
  • efficient PreparedStatement caching (Hibernate always uses PreparedStatement for calls to the database)
  • JDBC 2 style batch updates
  • Pluggable connection pooling

Hopefully you will agree that Hibernate approaches the parsimony of the best hand-coded JDBC object persistence. As a subscript I would add that I have rarely seen JDBC code that approaches the efficiency of the "best possible" code. By contrast it is very easy to write efficient data-access code using Hibernate.

So why don't you provide an "official" Hibernate benchmark?

Many people try to benchmark Hibernate. All public benchmarks we have seen so far had (and most still have) serious flaws.

The first category of benchmarks are trivial micro benchmarks. Hibernate of course will have an overhead in simple scenarios (loading 50.000 objects and doing nothing else is considered trivial) compared to JDBC. See this page  for a critique of a trivial benchmark. If you'd like to avoid writing your own trivial and not very conclusive tests, have a look at the perftest target in Hibernate's build file. We use this target to check if a trivial performance bug slipped into the Hibernate code. You can use it to verify the JDBC overhead of Hibernate in trivial situations. But, as should be clear now, these numbers are meaningless for real application performance and scalability.

In a fair benchmark with complex data associations/joins, highly concurrent access, random updates of data in the application, real-world data set size, and utilizing other Hibernate features, you will find Hibernate perform very well. Why is there no such benchmark provided by the Hibernate developers? The first reason is trust. Why would you believe that the numbers shown by the vendor of a product, in a comparative benchmark, are true? The second reason is applicability. Certainly, a fair benchmark would show the benefits of Hibernate in a typical complete application with realistic concurrent access. However, the number of variables in any decent benchmark make it almost impossible to transfer these results into reasonable conclusions about the performance of your own application. Your application is different. (If you came here from a forum thread, think about it: instead of arguing with you about your trivial micro benchmark, we would be arguing why you don't see the same results in your application...) For these reasons we always recommend that you benchmark your application yourself. We encourage you to see performance and load testing as a natural stage in the life of your application - don't go into production with only micro benchmarks. Setting up benchmarks for your application and scenario, and helping you in this stage is in fact one of our usual support and consulting services.

Conclusion?

It turns out that Hibernate is very fast if used properly, in highly concurrent multi-user applications with significant data sets.

Hibernate annotations faqs

I have migrated to a newer version and something went wrong

Please check the Java Persistence Migration Guide

I can't EAGER more than one collection !?

I get an exception when I load more than one collection !?

Yes you can, here are the solutions:
  • do not use a bag semantic: use a Set or a List annotated with @IndexColumn
  • use a @CollectionId
  • use @FetchMode(SELECT) or @FetchMode(SUBSELECT)

The underlying reason is that you cannot load more than one bag semantic collection in a given SQL query conceptually, so you won't find this feature in other products either.

I use @org.hibernate.annotations.Entity and get an Unknown entity exception

Always import @javax.persistence.Entity

@org.hibernate.annotations.Entity completes @javax.persistence.Entity but is not a replacement

I have AnnotationException: No identifier specified for entity

Set @Id in one of your property or field. Placing it on a field or a method will define the access type strategy

I'm having NoSuchMethodException(s)

Not all Hibernate Annotations versions works with every Hibernate Core version. Be sure to use the appropriate Hibernate core version (and the embedded version of ejb3-persistence.jar).

How to make the reverse engineering tools create an appropriate annotated composite id?

The reverse engineering mechanism from DB to the annotated domain model is currenlty in alpha stage. Composite ids are not yet properly handled.

Where can I see the hbm.xml files generated from the Annotations?

You can't. The annotations are building the internal Hibernate metadata model without any indermediate xml file.

I have issues with the schema creation with Derby

Derby has some limitations that prevent the DDL generation to work properly.

@Serialized was working for me, and now that I use @Lob it fails

Due to a change in the EJB3 specification, @Serialized is gone and has been replaced by a mapping through a blob. Many JDBC drivers have issues with Blob. @Serialized can be replaced by @Type(type="serializable").

How can I set inverse="true"?

The semantic equivalent is mappedBy in the association annotations. Have a look at the reference guide for a complete explaination.

How do I persist my superclass properties?

Annotate your superclass with @MappedSuperclass (This behavior changed compared to earlier implementations of Hibernate Annotations).

My Annotated class will not load

If you did not annotate with javax.persistence.Entity the AnnotationConfiguration class will ignore it. In particular, be sure you did not use org.hibernate.annotation.Entity by mistake. A good test is to use programmatic configuration via AnnotationConfiguration.addAnnotatedClass() rather than a hibernate.cfg.xml entry for the class in question.

Hibernate miscellaneous faqs

Unit Testing

I get a ClassCastException (or another "weird" exceptioin) when I try to call Hibernate from inside JUnit.

Fix 1 (Gareth Cronin)
Anyone using log4j/commons and JUnit should change the junit/runner/excluded.properties file inside junit.jar to look like this (it will get rid of all annoying Jakarta issues):

excluded.0=sun.* 
excluded.1=com.sun.* 
excluded.2=org.omg.* 
excluded.3=javax.* 
excluded.4=sunw.* 
excluded.5=java.* 
excluded.6=org.xml.sax.* 
excluded.7=org.w3c.dom.* 
excluded.8=org.apache.log4j.* 
excluded.9=org.apache.commons.*

Fix 2 (Eric Everman)
Another fix for this is to turn off class reloading in JUnit.

Toolset

How do I specify the length of a column for the SchemaExport tool? A unique column? A not-null column?

Column lengths and constraints may be specified in the mapping document. If you browse the mapping DTD you will find it quite well documented. There is also a chapter about it in the reference documentaiton.

I don't like the column type in the generated table creation script!

You can customize the column type using the <column> element, eg.

<property name="amount" type="big_decimal">
    <column sql-type="NUMERIC(11, 2)" not-null="true"/>
</property>

How can I embed table export functionality in my application?


Configuration cfg = ...;
new org.hibernate.tool.hbm2java.SchemaExport(cfg).create(true, true);

How can I make SchemaExport create InnoDB tables in MySQL

Use

delimiter=type=InnoDB

in the hbm2ddl configuration. Note that it will create a proper script file but the DDL execution statements done by SchemaExport won't use the delimiter, and thus won't create the table as InnoDB.

Rod Cope
If you're okay with having all table creation default to type=InnoDB when not otherwise specified, you can start your MySQL server with

--default-table-type=InnoDB

The SchemaUpdate tool doesn't work

SchemaUpdate relies upon the JDBC metadata API, which is implemented badly, inconsistently, or not at all by JDBC driver vendors. We have found it very difficult to make this tool work on all platforms at once.

The hibernate.hbm2ddl.auto=update setting doesn't create indexes

SchemaUpdate is activated by this configuration setting. SchemaUpdate is not really very powerful and comes without any warranties. For example, it does not create any indexes automatically. Furthermore, SchemaUpdate is only useful in development, per definition (a production schema is never updated automatically). You don't need indexes in development.

Hibernate doesn't generate the database indexes I want in the schema!

Automatic schema export (and update) by Hibernate tools is only useful in development. You never need indexes in development, they are purely for performance and scalability tuning in production systems. Production schemas are never automatically generated, at least not completely. A DBA adds indexes to the automatically generated schema during SQL tuning and testing of the application, before going into production with the (possibly automatically generated) base schema, and her handwritten optimized DDL. Also note that optimized DDL is highly vendor specific and totally dependent on the environment (SQL execution plans, tablespace configuration, caches, etc). Even if Hibernate developers would encourage you to automatically generate production-ready schemas (we don't, and we also don't like ad-hoc SQL tuning by throwing a bunch of indexes onto a schema), Hibernate could never offer such a feature.

Configuration

Whats the easiest way to configure Hibernate in a plain Java application (without using JNDI)?

Build a SessionFactory from a Configuration object. See the tutorials in the reference documentation.

Whats the easiest way to configure Hibernate in a J2EE application (using JNDI)?

Build a SessionFactory from a Configuration object. See the tutorials in the reference documentation. Specify a name for the SessionFactory in the configuration file, so it will be bound automatically to this name in JNDI.

How do I configure Hibernate as a JMX service in JBoss

See Using Hibernate with JBoss.

How do I use Hibernate in an EJB 2.1 session bean?

  1. Look up the SessionFactory in JNDI.
  2. Call getCurrentSession() to get a Session for the current transaction.
  3. Do your work.
  4. Don't commit or close anything, let the container manage the transaction.

How do I configure logging?

Hibernate uses the Apache commons-logging abstraction layer to support whichever logging framework you hapen to be using. See

http://jakarta.apache.org/commons/logging.html

To configure log4j you need to do two things:
  1. put log4j.jar in your classpath
  2. put log4j.properties in your classpath

There is an example log4j.properties in the hibernate-x.x directory. Just change INFO to DEBUG to see more messages (and move it into the classpath).

To use JDK1.4 logging, do three things:
  1. remove log4j.jar from the classpath
  2. run under JDK1.4
  3. configure logging via the properties file specified by the java.util.logging.config.file system property (this property defaults to $JAVA_HOME/jre/lib/logging.properties)

How do I configure the cache?

See the Performance Tuning chapter in the reference documentation.

Hibernate Generic Faqs

I get an OutOfMemoryException when I redeploy on Tomcat!

This  is common and not the fault of Hibernate or anything Hibernate does.  Hibernate has no leaking ThreadLocal variables, no classloader magic,  nothing else that has ever been identified as causing this and could be  somehow fixed in Hibernate. Tomcat's reloading of the web contexts  doesn't work reliably with other libraries (such as Struts, etc), the  reasons are often found in Tomcat, Classloaders, or JVM bugs. Please  don't post any questions about this on the Hibernate forums, or on the  Hibernate developer list. Ask on the Tomcat users list. If you need hot  redployment to work immediately, use Tomcat inside JBoss application  server.

Can I use Hibernate with JDK 1.3?

Yes,  but the distributed binaries are compiled for JDK 1.4 and newer. You  will have to recompile Hibernate from source (type 'ant' in the  distribution directory). This probably fails, as some of the  dependencies of Hibernate have been compiled or are only available for  JDK 1.4 and newer. However, users reported success after they found  replacements for these dependencies.

Hibernate doesn't work with MySQL!

The  MySQL Server 4.1.12 RPM delivered with Mandriva Linux 2006 breaks  prepared statements. This can be solved by either adding  "useServerPrepStmts=false" to the MySQL connection string in the  Hibernate configuration file or by using an unbroken original MySQL  Server package. http://bugs.mysql.com/bug.php?id=14910

Hibernate expects my JDBC driver to support JDBC2 but it doesn't!

Set

hibernate.jdbc.batch_size=0
hibernate.jdbc.use_scrollable_resultsets=false

or  upgrade your driver to the latest version. Hibernate chooses sensible  default values for these properties, based upon your SQL dialect.

My JDBC driver supports batch updates. How come Hibernate doesn't enable them by default?

Batch  updates seem to be cause problems for some JDBC drivers that claim to  support them. We found that batch updates should be disabled for DB2 and  Sybase.

Hibernate doesn't work with my MS SQL 2000 JDBC driver?

(Glen Stampoultzis)

If you're using Hibernate with the Microsoft SQL Server 2000 JDBC driver chances are you'll run into this problem:

java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]
Can't start a cloned connection while in manual transaction mode.

Simply add SelectMethod=Cursor; to your connection string. There's a MS knowledge base article with more information. The Microsoft SQL Server 2005 JDBC driver has been certified by JBoss Inc.

Are there known issues with Interbase / Firebird?

(Michael Jakl)

Yes. Due to some limitations in Interbase / Firebird we must use some workarounds:

Always set the size of your statement cache to zero (hibernate.statement_cache.size or hibernate.c3p0.max_statements)

If you are altering tables you should be in single user mode. This can be achieved by running gfix -shut.  It's also sufficient to have only one database connection open (eg.  immediately after starting the application). If more than one connection  is open, you will see errors like "table is in use". To restart your  database use gfix -online.

I'm having problems with Weblogic Server!

If you get CharScanner; panic: ClassNotFoundException: org.hibernate.hql.ast.HqlToken  - Hibernate 3.x includes a new query parser that doesn't run on  Weblogic - the reason is a packaging error of ANTLR in Weblogic's boot  classpath. Read the section in the Hibernate3 Migration Guide.

If you have a = javax.naming.NoInitialContextException=, this seems to solve it for Weblogic 8.1, in your Hibernate configuration:

<property name="jndi.url">t3://localhost:7001</property> 
<property name="jndi.class">weblogic.jndi.WLInitialContextFactory</property>

The JNDI implementation in WebLogic Server does not appear to support the Referenceable interface, and exhibits some rather strange behaviour when binding Serializable objects. Please direct complaints to BEA. This might affect only older versions of Weblogic.

Workarounds include using a different JNDI implementation (eg. Sun's FSContext) or using some other means of obtaining a SessionFactory.

See also Mathias' Blog!

The forum users believe there's some problem if you do  it the regular way like most app server. Therefore, try the following  (which works for me). Use a WLS Startup class to bind Hibernate Session  Factory object in WLS JNDI. Here's an excerpt of a possible code:\

public class WLSStartup implements T3StartupDef
{
    public static final String SESSION_FACTORY_JNDI = "hibernate";
    public static final String URL = "t3://localhost:7001";
 
    /**
     * Called by WebLogic server upon startup. This is where everything should
     * be initialzed.
     *
     * @param   name        the JNDI name of this class
     * @param   args        any input parameters
     *
     * @return              the status.
     *
     * @throws  Exception   in case of any error
     */
 
    public String startup(  String name, Hashtable args ) throws Exception
    {
        String       METHOD_NAME        = "startup ";
 
        // Bind the various Hibernate Object to the Weblogic JNDI
        try
        {
            log ( METHOD_NAME + " Going to bind Hibernate object. " );
            doBind( );
            log ( METHOD_NAME + " Bound Hibernate object!" );
        }
        catch ( Exception exception )
        {
            log ( METHOD_NAME + " Exception while binding Hibernate Object to Weblogic JNDI" );
            exception.printStackTrace ( );
        }
 
        return "WLS Startup completed successfully";
    }
 
    /**
     * Performs Hibernate objects to Weblogic JNDI Namespace bindings.
     * It gets the initial context and binds the Hibernate objects to it.
     *
     * @param       None
     * @throws      Exception      in case of any errors
     */
 
    private static void doBind( ) throws Exception
    {
        Properties  environment  = null;
        InitialContext  context  = null;
 
        try
        {
            //Properties for storing JNDI configuration information
            environment = new Properties( );
 
            //Add initial context factory
            environment.put( Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
            environment.put( Context.PROVIDER_URL, URL );
            log( "Constructing an Initial Directory Context object" );
            context = new InitialContext( environment );            
 
            Datastore ds = Hibernate.createDatastore();
            SessionFactory factory = ds.buildSessionFactory();            
 
            if (factory == null)
                throw new Exception("SessionFactory cannot be built?!");
            
            try
            {
                if( context.lookup(SESSION_FACTORY_JNDI ) != null )
                    context.rebind(SESSION_FACTORY_JNDI, factory );
                else
                    context.bind(SESSION_FACTORY_JNDI, factory );
            }
            catch ( NamingException nameEx )
            {
                context.bind(SESSION_FACTORY_JNDI, factory );
            }            
 
        }
        catch ( NamingException nameExp )
        {
            throw new Exception( "NamingException: " + nameExp.getMessage( ));
        }
        catch( Exception excp )
        {
            throw excp;
        }
        finally
        {
            if( context != null )
            {
                try
                {
                    context.close( );
                    context = null;
                }
                catch ( NamingException nameExp )
                {
                    throw new Exception( "NamingException for context close: " nameExp.getMessage( ));
                }
            }
            environment = null;
        }
 
    }
}

Jar up the relevant Hibernate jar files and configure this Startup class under WLS console.

Then at your JNDI client (Servlet or EJBs for example) you can have a code similar to this excerpt below: -

Object objref;
Context context;
Hibernate.configure();
 
//The usual WLS JNDI context
context = getInitialContext(); 
objref = context.lookup(WLSStartup.SESSION_FACTORY_JNDI);
sessionFac = (SessionFactory) PortableRemoteObject.narrow(objref, SessionFactory.class);
 
if sessionFac == null)
       throw new Exception("Null SessionFactory found?!");

Works great with Struts 1.1 on WLS 6.X and 7.X. I've tested by writing some subclass relationship data into Oracle 8i!

Any questions can be directed to simon@see-consulting.com.

After a while, Oracle throws this exception: too many open cursors

The Oracle JDBC driver doesn't much like to have its prepared statements cached. Disable PreparedStatement caching for the connection pool.

MySQL throws an exception: Cannot disable AUTO_COMMIT

Download the latest MySQL driver.

Tomcat throws java.lang.UnsupportedOperationException when fetching a JDBC connection

In Tomcat (maybe other situations) if you are using the built-in DBCP to as a JNDI datasource, be sure that you do not specify hibernate.connection.username or hibernate.connection.password in either hibernate.cfg.xml or hibernate.properties. DBCP does not implement the version of Datasource.getConnection() that takes a username and password.

JBoss AS complains about unclosed connections?

If  you get the message  "[org.jboss.resource.connectionmanager.CachedConnectionManager] Closing a  connection for you. Please close them yourself:  org.jboss.resource.adapter.jdbc.WrappedConnection" you are missing a  configuration setting, hibernate.connection.release_mode - set it to auto or read the reference documentation about it.