Red Hat

In Relation To

The Hibernate team blog on everything data.

The Scope of Hibernate Three

Posted by    |       |    Tagged as Java EE

After more than a year of activity, development of the Hibernate2 branch has finally been wound up; Hibernate 2.1.3 will be one of the last releases and represents a rock-solid POJO persistence solution with essentially all the functionality needed by a typical Java application. Any future release of Hibernate 2.1 will contain only bugfixes. The branch that we have been calling 2.2, will actually be released as version 3.

The Hibernate project has previously had quite circumscribed goals - we have limited ourselves to thinking about just the very next release, and just what our users are asking for right now. That approach has finally reached the end of its usefulness. Hibernate3 is concieved in hubris, with the goal of innovating beyond what our users are asking for, or have even thought of. Certainly we will be adding features that go well beyond the functionality of the best commercial ORM solutions such as TopLink. (Some of these features will be most interesting to people working with certain specialized kinds of problems.)

So, in this spirit of hubris, I'll drop my normal policy of not boasting about things we have not yet implemented, and give a sketch of some of the things that are planned for Hibernate3 alpha (as usual, we do not commit to dates for future releases).

Virtualization

A number of important and interesting problems may be solved by presenting the user with a certain, filtered, subset of the data. For example, a user might want to see data valid at a particular point in time, or may have permissions to view data only in a particular region. Rather than forcing application code to specify this filter criteria in tedious query conditions, Hibernate 3 will allow the (parametrized) filters to be applied at the session level.

(This feature has not yet been implemented, though some of the needed refactorings are currently sitting on my laptop.)

More Mapping Flexibility

For the overwhelming majority of cases, Hibernate2 provides all the O/R mapping options you will need. However, there are now a few new features that are powerful, if used judiciously.

  • single-class-to-multiple-table mappings using <join>
  • table-per-concrete-class-mappings using <union-subclass>
  • flexible discriminators using SQL formula mappings

We have long argued favor of extremely fine grained classes, and have viewed multi-table mappings as a huge misfeature (except for the very important special case of table-per-subclass inheritance mappings). Unfortunately, several commercial vendors insist upon trying to spin this misfeature as an actual competitive advantage of their products, causing us regular irritation. So we have provided the <join> mapping mainly to shut them up.

Well, I do conceed that there is one great use-case for <join>. We can now mix together table-per-hierarchy and table-per-subclass mappings in the same hierarchy. For example:

<class name="Document" table="DOCUMENTS">
    <id name="id">...</id>
    <discriminator column="TYPE" type="string"/>
    ...
    <subclass name="Book" discriminator-value="BOOK"/>
    <subclass name="Newspaper" discriminator-value="NEWSPAPER"/>
    <subclass name="XML"  discriminator-value="XML">
        <join table="XML_DOCUMENTS">
            ....
        </join>
    </subclass>
</class>

Hibernate's implicit polymorphism is a nice way to achieve most of the functionality of table-per-concrete-class without placing unnatural restrictions upon column types of different tables. It also nicely allows table-per-concrete-class to be mixed with other inheritance mapping strategies in the same hierarchy. Unfortunately, it has two limitations:

  • we cannot have a polymorphic collection of the superclass type
  • queries against the superclass resolve to muktiple SQL queries, which could be slower than using an SQL UNION.

The new <union-subclass> construct provides an explicit way to map classes to a table-per-concrete-class model and is implemented using SQL UNIONs.

If your table-per-class-hierarchy mapping does not feature a nice simple discriminator column, where values map one-to-one to the different classes, formula discriminators are for you. You can now discriminate between subclasses using multiple columns, multiple values of the same column, arbitrary SQL expressions or functions, even subqueries! An example:

<class name="Document" table="DOCUMENTS">
    <id name="id">...</id>
    <discriminator type="string"
        formula="case when TYPE='MONOGRAPH' then 'BOOK' when type='TABLOID'\
        or type='BROADSHEET' then 'NEWSPAPER' else TYPE end"/>
    <property name="type" column="TYPE"/>
    ....
    <subclass name="Book" discriminator-value="BOOK"/>
    <subclass name="Newspaper" discriminator-value="NEWSPAPER"/>
</class>

All of these features have been implemented in the Hibernate3 branch.

Representation Independence

Hibernate was conceived as a persistence solution for POJO domain models, and that remains the focus. Occasionally, we run into people who would like to represent their persistent entities in some more dynamic way, as a map, essentially. We used to point them to OFBiz Entity Engine. Well, Hibernate3 lets you represent your domain model as trees of HashMaps, or, with a little bit of user-written code, as just about anything. Here are three immediate applications of this new feature:

  • reimplement JBoss CMP 2.1 engine on top of Hibernate
  • reimplement OFBiz EntityEngine using Hibernate
  • natively persist SDOs

Indeed, the end goal is to allow the application to switch between whichever representation is appropriate to the task at hand; the same entity might be represented as a typesafe POJO, a Map, or an SDO, all with just a single Hibernate mapping.

This feature has been implemented in the Hibernate3 branch.

JDK 1.5 Support

JSR 175 annotations are a perfect fit for Hibernate metadata and we will embrace them aggressively. Emmanuel Bernard is working on this.

We will also need to support Java generics, which basically boils down to allowing typesafe collections (which is very trivial).

Stored Procedure Support

We are not enormous fans of using stored procedures for CRUD operations (of course, there are some other use cases where SPs make wonderful sense) but people working with legacy databases often need Hibernate to call a SP instead of generating its own SQL statement. In Hibernate 2.1, it is possible to achieve this with a custom persister. Hibernate3 will allow arbitrary SQL statements to be specified in the mapping document for create, update and delete. Max Andersen is currently implementing this feature.

Full Event Driven Design

In the early days of the project, I applied YAGNI aggressively. Hibernate was occasionally criticized for supposed architectural deficiencies, due to the absence of a clear upfront design. (In my view, this lack of upfront design was not actually an architectural problem - at least by my understanding of the word architecture - but that debate is for another day...) Anyway, it was my firm belief that an elegant and flexible design would eventually grow naturally, and that our scarce attention and development resources were better spent solving actual user-visible problems. I now feel quite vindicated in this decision; Hibernate has flourished, and the design that has emerged is both powerful and reasonably elegant. Take that, YAGNI-skeptics!

There is one final step of this process, that is now in the hands of Steve Ebersole (and already partially implemented). Hibernate3 will feature an event-oriented design, with event objects representing any interesting thing that occurs, and listener classes that implement standard Hibernate behaviours, or customized user-defined behaviors. This user extension capability has applications ranging for auditing to implementing strange cascade semantics. (Our previous attempt to solve these problems - the Interceptor interface - proved to be insufficient.) Importantly, the redesign simplifies the current monolithic SessionImpl class.

New AST-driven Query Parser

Well, actually /two/ final steps. (No-one expected the Spanish inquisition, did they?)

When I wrote the HQL parser, I knew zip about parsers. Hibernate ended up with a wierd-ass handwritten pure-look-behind parser which, to my great and enduring surprise, has actually served us very well and been the source of very few bugs. (YAGNI, once again.) But it is now well past time we had a proper ANTLR-grammar-based AST, and Joshua Davis is currently writing one. This probably won't mean much in the way of user-visible changes, but it should allow us to more easily support other query languages such as EJBQL.

Declarative Session Management

This is a JBoss-specific feature for now. New users often find session management to be tricky at first. It can take a bit of thought to get your head around the schizophrenic role played by the Hibernate session as both a kind of cache, and a kind of connection. A JDBC Connection is stateless; a Hibernate Session, on the other hand, is a stateful connection! We further confuse the issue by telling people that, actually, the session is really representing a kind of transaction!

Rather than force people to implement their own session handling, messing with threadlocals and exception handling, it would be nice to have some way to specify the session model (session-per-database-transaction, or session-per-application-transaction) declaratively, in the metadata for a session bean. The Spring Framework already provides some support for this kind of approach. Michael Gloegl is working on implementing this functionality using a JBoss Interceptor. It would be wonderful to have this facility in appservers other than JBoss. J2EE needs portable Interceptors for EJBs (they already exist for servlets).

Well, I have some more things on my list, but that will do for now!

SQL Tuning

Posted by    |       |    Tagged as

If you ever work with relational databases, you should go out and buy O'Reilly's /SQL Tuning/, by Dan Tow. The book is all about how to represent a SQL query in a graphical form and then, using some simple rules of thumb, determine an optimal execution plan for the query. Once you have found the optimal execution plan, you can add indexes, query hints, or use some other tricks to persuade your database to use this execution plan. Fantastic stuff. There is even sufficient introductory material for those of us (especially me) who know less than we should about the actual technical details of full table scans, index scans, nested loops joins, hash joins, etcetera to be able to start feeling confident reading and understanding execution plans. Unlike most database books out there, this book is not very platform-specific, though it does often refer specifically to Oracle, DB2 and SQL Server.

Java Webstart enabling Hibern8IDE - no luck!

Posted by    |       |    Tagged as

Recently I have been messing with adding custom class loading to Hibern8IDE, so it can load model and database driver classes at dynamically.

This allows us to run Hibern8IDE standalone instead of requiring users to run it from their actual project (which of course still is possible ;)

The 'trick' is as follows:

Thread thread = Thread.currentThread();
ClassLoader prevCl = thread.getContextClassLoader();
   try {
       List urls = ... // a list of paths/zips/jars for the classloader
       if(urls.size()>0) {
            URLClassLoader _newLoader = new URLClassLoader((URL[]) urls.toArray(new URL[0]), thread.getContextClassLoader());
            thread.setContextClassLoader(_newLoader);
            }                   
        // convince DriverManager that you can use our specified driver!
        String driverClass = props.getProperty("hibernate.connection.driver_class");
        if(driverClass!=null) {
        try {
            Class driverClazz = ReflectHelper.classForName(driverClass);
            DriverManager.registerDriver(new FakeDelegatingDriver((Driver) driverClazz.newInstance()));
            } catch (... e1) {               
            }
        }
        configuration = new Configuration();
        configuration = configuration.setProperties(props);
        configuration = configuration.configure(configfile);
        
        Iterator hbms = mappings.iterator();
        
        while (hbms.hasNext()) {
            hbm = (File) hbms.next();
            configuration = configuration.addFile(hbm.toString());
         }
         
         initialize(); // build sessionfactory etc.
        } catch (... e) {
       } finally {
        thread.setContextClassLoader(prevCl);
       }

The code does two things install Hibern8IDE custom classloader while loading the mappings and jdbc drivers PLUS install a FakeDelegatingDriver to convince the stupid java.sql.DriverManager that it is ok to load jdbc drivers from other places than the system classloader.

And this works!, but not when trying to Java Webstart enabling Hibern8IDE :(

It seems like Java Webstart is very strict about it's permission policy even though a <all-permission/> tag are in the JNLP file :(

The loading of model classes and drivers works smoothly, but as soon as the driver wants to connect to the database a security exception is throwing saying the application is not allowed to connect to a port on the database machine :(

So, for now Hibern8IDE is available in a standalone version, but unfortunately not via Java Webstart because of it's strictness!

Any bright ideas are welcome!

Finalizers are even eviler than you think

Posted by    |       |    Tagged as

Developerworks is featuring the best article I have ever read on the subject of Java performance. The authors dispose of the canard that temporary object creation is expensive in Java, by explaining how generational garbage collection works in the Sun JVM (this is a bit more detailed explanation than the typical one, by the way). Well, I already knew this; Hibernate rejected the notion of object pooling right from the start (unfortunately, the EJB spec has not yet caught up).

What I did /not/ know was that objects which implement finalize() require two full garbage collection cycles to be released. Now, everyone knows that finalize() cannot be relied upon and we should not write important code in a finalizer. But /this/ finalize() method, taken from Hibernate's SessionImpl class seemed like a really good idea:

/**
 * Just in case user forgot to call close()
 */
protected void finalize() throws Throwable {
  
  log.debug("running Session.finalize()");
  
  if (isCurrentTransaction) log.warn("afterTransactionCompletion() was never called");
  
  if (connection!=null) { //ie it was never disconnected
    if ( connection.isClosed() ) {
      log.warn("finalizing unclosed session with closed connection");
    }
    else {
      log.warn("unclosed connection");
      if (autoClose) connection.close();
    }
  }
}

The main thing that this method is doing is checking to see if the naughty application forgot to close the session and, if so, log a WARN. This is a really good idea! It is otherwise quite hard to noticed unclosed sessions, and the JDBC connections they own. Unfortunately it has the terrible side-effect of preventing the session from being garbage collected immediately. Now, even after reading the article, I didn't think that this would be such a big deal, since I dereference almost all of the session's state from close(). However, My performance tests are showing a really /big/ difference in performance, just from removing the finalizer. For one problematic test, I actually /halved/ the overhead of Hibernate!

I can barely believe this result, but I've been successfully reproducing it for the last two hours.

Not so Naked Objects

Posted by    |       |    Tagged as

Currently I have noticed that Naked Objects gets more and more blog-time. And every time I wondered why (many?) people found it so intriguing - and I often thought about making a blog about the good and bad about Naked Objects; but I've never found the time.

I still don't have the time to do a detailed blog about it, but just state some facts and/or criticism about the implementation of Naked Objects that I've can't remember seeing listed before.

A. All objects has to implement NakedObject or extend AbstractNakedObject (actually some code in the framework assumes every object is an AbstractNakedObject...but that I guess they will fix a some point).

B. All fields that you want the framework to know about need to be a NakedValue, thus String has to be a TextString, float a FloatingPointNumber, etc. This is all basically done to let the values be mutable and add all the linguistic needs for their (all to easy to criticize, so I won't) automatic GUI.

C. All collections of associated objects need to be NakedCollection which definitly is not in any way a standard java.util.Collection (because they also do not use anything from jdk 1.2, just to be able to run on .Net!).

Each of point A, B and C makes me not like the Naked Objects framework (at least the implementation)! Why ? Because all my objects won't be POJO's anymore - and especially item C, makes it very hard to e.g. use Hibernate (or many other reflection based ORM's) to persist these not so Naked Objects. It at least require some very specific Naked Object code to make it work.

And when we are talking about persistence, then the whole framework does have a built-in persistence engine which is pluggable - but it's very simple, and transaction demarcation looks very hard to control, if even possible at the moment.

But enough harsh criticism ;), the good stuff is their ideas about behavioral complete objects (BCO). From the book: an object should completely model the behavior of the thing that it represents. ... most people continue to design business systems that separate procedure from data, albeit dressed up in the language and technology of object-orientation.

And I do agree to that point - people do get to procedural at times, myself included, and if Naked Objects help us do that a little less I would appreciate it.

Their automatic (and empowering to the users as they call it) UI, is somewhat interesting - but geez, they seriously got to look more into ui design ;) (and yes, I know they did look into ui design to empower their users, but I simply don't think their UI has value in other areas besides being provocative and different ;)

And as I understand the authors then it is the BCO and the automatic created UI that is their focal point, but I don't understand why they have not utilized existing technologies that is close to almost do the same....like the JavaBeans API ? JavaBeans is more than just a naming standard for properties! It was build for allowing IDE's to inspect objects and build intelligent UI's!

It got an Introspection API which one could use to discover all the details of an object and the API is extensible in a much more non-intrusive way than Naked Object does it.

What about using standard property listeners ? Why limit you to use jdk 1.1 ? Who want's to only use Vector, and why not utilize the Collections API interfaces to make their object structure much more standard compliant ?

In the end I encourage the authors to work on their core concepts: BCO and automatic UI's (even though I don't think it will cover more than a few useful applications). But they should really look into using more JDK API's for this, so the framework becomes more useful in real-life applications.

P.S. And why is their catch all blocks and printStackTrace() multiple places in the source of a system that candidates for being used in more than just prototype systems ?

Wrestling With Pigs

Posted by    |       |    Tagged as

I have to repeat this cliche to myself at least once a week:

/Never wrestle with a pig; you both get dirty and the pig loves it./

One of the problems with online forums is that, naturally, they are dominated by the people with the most time on their hands - and by the people with the most dogmatic views. As in any community, the loudest views are often the least-informed. When criticized in a forum like TSS , it's usually better to just stay out of the mud. As difficult as it is to let uninformed statements go unchallenged, it is almost always the best decision. Let the pig be. Disputing a post brings attention to it. If the poster is of a particular personality type, the disputation will very quickly turn personal. Maintaining your dignity once that happens is virtually impossible.

In fact, what most amazes me about IT communities is the sheer ubiquity of /argumentum ad hominem/. I've always associated computing with the pursuit of understanding via scientifically inclined methodology. Yet most of the debate that occurs in the Java community consists of name-calling. I got so mad about this today that I broke all my own rules and launched some /ad hominem/ of my own, which is really quite self-defeating, I suppose.

The big problem from my point of view is that I can't simply ignore the online forums; as an open source project they are an absolutely indispensible way for us to get our ideas heard.

Clay Shirky has written insightfully about how online communities can be designed, so it is interesting to speculate about what kind of adjustments could be made to a community like TSS if we wanted to bring out our good sides, and encourage technical arguments rather than personal ones. But perhaps the very strength of TSS is the freewheeling nature of the debate there. Flame wars get attention; they generate the most traffic.

Well, I'm a big boy. Hibernate has been subject to all kinds of outlandish criticisms right from the start. But we are growing every month. We often joke that criticisms of Hibernate invariably begin with I've never used Hibernate but... and indeed that is still true. If our actual /users/ start bitching, /then/ we will need to start listening harder!

Apologies for the nontechnical post ;)

Hibernate 2.1.2

Posted by    |       |    Tagged as Hibernate ORM

I just released 2.1.2 . This is a maintenence release, meaning no especially exciting new features (the interesting work is all going on in the 2.2 branch). However there are some small changes that might make a big performance difference in certain specific cases, especially if you are using a second-level cache. I'm hoping that this release brings the 2.1 branch to the same level of maturity that we were able to achieve with 2.0.3.

Books for free...

Posted by    |       |    Tagged as Java EE

This is a reply on the Hibernate forum, read the full thread for the context.

As some noticed, I'm a bit impulsive about that kind of thing right now. We get one question a day, sometimes friendly, sometimes not so friendly, if we could just set up the book (Hibernate in Action) for free download or simply send it over.

Don't take it personal if I'm getting annoyed about that. It's sometimes just embarrassing when someone gives you the feeling that you owe them something, just because they use Hibernate. I'd like to explain why its not about the money for the book.

First, and that is really my own personal opinion, a professional Java developer should have enough money for whatever book in any case. Books are important, read at least one each month, better two. I don't buy any of that offshore jobs talk, but knowledge is the only thing that keeps you in business. I don't want to discuss $5 Amazon shipping costs about that.

Now I'd like to start a little rant here, so you better stop reading if you are not in the mood :)

Our software is free, our documentation is of course free, and we will always provide free support on a personal level in this forum, and whenever we think it is needed.

I also think that our software and the whole project shows that we are serious about what we are doing. We worked many nights and weekends last year. Gavin and me quit our jobs to make this possible. Max, David, Steve, Emmanuel spend hours a day after work, writing interesting things and answering questions (now up to 120/day) on the forum.

We really believe in professional open source as a business model in the software sector. Actually I'm now also employed by JBoss Group. We have two people working fulltime on Hibernate.

How do we earn our salary?

With open source, there are no license fees. This is great for developers, as they can sell the software they'd like to use to their project managers and accountants easily. Well, of course only if all the other qualities are right:

  • good software
  • good documentation and free support
  • commercial support (risk management)
  • nice extras

A successful vendor of closed software can provide the second for free, but you have to pay for the other three most of the time. Sometimes its hidden, sometimes not. The situation is quite different with an open source software project. First, there are no hidden costs, because you actually can't hide anything. Second, we as software developers don't like hiding any costs somewhere, we are not good with that kind of thing. It's much easier to tell people what they need and what it costs upfront. I also like the look on peoples faces if you admit that Hibernate solves only 95% of their problems, not 100! Shocking! The truth!

It's hard to break with the traditions and I remember the early Linux days when it was first used used commercially. You actually had to tell people that free software is good because they don't pay money for licenses. They wouldn't believe you, just don't ask for a (real) reason. Usually they expected some hidden costs in the other three items and simply denied that it was any good at all.

Sometimes, I think it was too much propaganda back then, now everyone expects everything for free!

To support a business, some revenue must be made from at least one of the four elements I listed.

I'm not talking about the book, because that really doesn't pay. I think most people know that books don't pay in the end, at least if your name is not Fowler or Bloch. Why do we write it then? It helps us to get more people (and therefore ideas and opinions) into Hibernate, and we can finally write down some thoughts we can't express in any other medium.

And yes, we also hope that it will help us to grow the Hibernate business. Thats our job. There is no professional quality without that background, or at least not for a long period of time.

Hibernate is naturally a very open project driven by the users. This will not change, no matter what our business model is. We think that listening to users and balancing requests is the heart of the project, it is the reason why people like it and why it works(tm).

If you are having problems...

Posted by    |       |    Tagged as

I just finished a consulting job at a large retailer where we managed to increase the performance of a Hibernate application by perhaps two orders of magnitude with just some fairly simple changes. It really drove home to me how almost all performance problems I've ever seen can be solved by either or both of:

  • appropriate session handling
  • appropriate association fetching strategies

(Note that I have not yet met a serious performance problem in Hibernate 2.x that I could not solve quite quickly.)

Hibernate's Session object is a powerful abstraction that allows some extremely flexible architectural choices. Unfortunately, this flexibility comes at a cost: many people seem to stuff it up! There are three well-understood patterns for managing Hibernate sessions correctly (actually, three-and-a-half, as I've recently discovered) and three common antipatterns. The fact that the antipatterns are more common than they should be suggests a real problem with our existing documentation, and highlights the fact that /we need to get this book out!/

The main reason we've previously been unable to explain the correct ways to handle Hibernate sessions is that we simply havn't had a decent language for describing our ideas. Since we've developed this language in the process of writing the book, explanations are much easier. The key concept is the notion of an /application transaction/. An application transaction is a unit of work from the point of view of the user; it spans multiple requests and multiple database transactions - it does, however, have a well-defined beginning and end. Even if you don't currently use this notion explicitly, you probably /do/ use it implicitly in your application.

Briefly, the three acceptable approaches are: session-per-request, session-per-request-with-detached-objects and session-per-application-transaction. A variation of the third approach is the newly-discovered session-per-application-transaction-with-flush-delayed-to-the-last-request (phew!). The three broken approaches are: session-per-operation (ie. many-sessions-per-request), session-per-user-session and session-per-application. If you are using any of these approaches, please stop.

The three acceptable approaches each have different performance and architectural implications and there is no best solution. It is incredibly important to choose the approach that is most suitable to your particular application (this was the key to the two-orders-of-magnitude improvement described above).

Association fetching is, I think, covered quite well in our documentation, but we still sometimes see people struggling with the dreaded n+1 SELECTs problem. So let me be very clear: Hibernate /completely/ solves the n+1 SELECTs problem! However, it takes some thought and a (very) little work on the part of the user to take full advantage of this fact. We recommend that all associations be configured for lazy fetching by default. Then, for particular use cases, eager outer join fetching may be chosen by specifying a LEFT JOIN FETCH clause in a HQL query, or by calling setFetchMode() for a Criteria query. (If you are too lazy to do this work, you could even try the new batch fetching features of Hibernate 2.1. We don't recommend this less elegant approach, however.)

Less common performance problems may be fixed by using a second-level cache, or occasionally by managing flushing manually (set the session flush mode to FlushMode.NEVER and flush manually when required). However, in almost all cases, acceptable performance can be achieved by concentrating upon the two items listed above.

Don't lock in the middle tier!

Posted by    |       |    Tagged as

One of the reasons we use relational database technology is that existing RDBMS implementations provide extremely mature, scalable and robust concurrency control. This means much more than simple read/write locks. For example, databases that use locking are built to scale efficiently when a particular transaction obtains /many/ locks - this is called /lock escalation/. On the other hand, some databases (for example, Oracle and PostgreSQL) don't use locks at all - instead, they use the multiversion concurrency model. This sophisticated approach to concurrency is designed to achieve higher scalability than is possible using traditional locking models. Databases even let you specify the required level of transaction isolation, allowing you to trade isolation for scalability.

Unfortunately, some Java persistence frameworks (especially CMP engines) assume that they can improve upon the many years of research and development that has gone into these relational systems by implementing their own concurrency control in the Java application. Usually, this takes the form of a comparatively crude locking model, with the locks held in the Java middle tier. There are three main problems with this approach. First, it subverts the concurrency model of the underlying database. If you have spent a lot of money on your Oracle installation, it seems insane to throw away Oracle's sophisticated multiversion concurrency model and replace it with a (less-scalable) locking model. Second, other (non-Java?) applications that share the same database are not aware of the locks. Finally, locks held in the middle tier do not naturally scale to a clustered environment. Some kind of distributed lock will be needed. At best, distributed locking will be implemented using some efficient group communication library like JGroups. At worst (for example, in OJB), the persistence framework will persist the locks to a special database table. Clearly, both of these solutions carry a heavy performance cost. Accordingly, Hibernate was designed to /not require/ any middle-tier locks - even thread synchronization is avoided. This is perhaps the best and least-understood feature of Hibernate and is the key to why Hibernate scales well. So why do other frameworks not just let the database handle concurrency?

Well, the only good justification for holding locks in the middle tier is that we might be using a middle-tier cache. It turns out that the problem of ensuring consistency between the database and the cache is an extremely difficult one and solutions usually do involve some use of middle-tier locking. (Incidently, most applications which use a cache do not solve this problem correctly, even in a non-clustered environment.)

So, for example, when Hibernate integrates with JBoss Cache, the cache implementation must obtain clustered locks internally (again, using JGroups). In Hibernate, we consider it a quality-of-service concern of the cache implementation to provide this kind of functionality. We can do this because Hibernate, unlike many other persistence layers, features a two-level cache architecture. This design separates the transaction-scoped /session cache/ (which does /not/ require middle-tier locking and delegates concurrency concerns to the database) from the process or cluster scoped /second-level cache/ (which /may/ require middle-tier locks). So when the second-level cache is disabled for a particular class, no middle-tier lock is required. Hence, in this case, the scalability of Hibernate is limited only by the scalability of the underlying database. Our design also allows us to consider other, more sophisticated approaches to ensuring consistency between the second-level cache and database - approaches that do not require the use of middle-tier locking. I'll keep this stuff secret for now; it is an active area of investigation!

back to top