Version 27

    JBoss-Hibernate Integration (Hibernate 3)

    - Steve Ebersole, JBoss Inc

    - Ales Justin, JBoss Inc


    Hibernate support within JBossAS is provided by 3 high-level components:

     

    1. Hibernate MBean - provides deployment, lifecycle, and management support around a Hibernate SessionFactory;

    2. HAR Deployer - defines a Hibernate ARchive as a new deployable unit within JBoss AS;

    3. Session Management - provides transparent management of Hibernate sessions.

     

    A fourth (org.jboss.hibernate.cache.DeployedTreeCacheProvider) is intended to more cleanly integrate Hibernate with JBossCache, when JBossCache itself is a deployed service.

     


    Hibernate MBean

     

    The Hibernate MBean is responsible for constructing a Hibernate SessionFactory

    and exposing it through JNDI. It also provides JMX management capabilities

    around the deployed SessionFactory such that its configuration can be modified

    at runtime.

     

    It exposes a number of configuration properties which affect the runtime behaviour of Hibernate. The more important of these include:

     

    • DatasourceName - the JNDI name of the datasource Hibernate should use;

    • Dialect - the RDBMS dialect;

    • SessionFactoryName - the JNDI name where the constructed SessionFactory

    should be bound;

    • CacheProviderClass - the Hibernate CacheProvider class to use for its second-level cache.

     

    Check out the Javadocs for org.jboss.hibernate.jmx.Hibernate for a complete list of the available configuration properties.

     

    Notice that there is no option to specify the mapping documents to load. That is because the Hibernate MBean is meant to work in conjuction with the HARDeployer component and gets this information from there.

     

    Here is an example of configuring the MBean:

    <mbean code="org.jboss.hibernate.jmx.Hibernate" name="jboss.har:service=Hibernate">
      <attribute name="DatasourceName">java:/DefaultDS</attribute>
      <attribute name="SessionFactoryName">java:/hibernate/SessionFactory</attribute>
      <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
      <attribute name="CacheProviderClass">org.hibernate.cache.HashtableCacheProvider</attribute>
      <attribute name="Hbm2ddlAuto">create-drop</attribute>
    </mbean>
    

    <attribute name="ShowSqlEnabled">true</attribute> should be used to show

    the sql output, instead of the former

    ShowSql

    attribute.

     


    Hibernate (M)Bean in JBossAS5

     

    A Hibernate MBean usage was rewritten in the new JBossAS5.

     

    Previously you added the mbean directly to your jboss-service.xml, where it was able to get the mapping files from underlying URLClassloader. With the change to more strict classloader environment (and not being a URLClassloader instance), this is not possible anymore. So in order for JBossAS to automatically find the mapping resources, we need to provide that information from the VDF (VirtualDeploymentFramework, aka deployers).

     

    To simplify transformation from hibernate.cfg.xml even more, we now support direct hibernate schema, plus additional depends element, which is useful to declare some external dependencies on existing beans, e.g. TransactionManager.

     

     

    What was previously

    <server>
    
       <mbean code="org.jboss.hibernate.jmx.Hibernate"
              name="jboss.test.har:service=Hibernate,testcase=TimersUnitTestCase">
          <attribute name="DatasourceName">java:/DefaultDS</attribute>
          <attribute name="SessionFactoryName">
             java:/hib-timers/SessionFactory</attribute>
          <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
          <attribute name="SessionFactoryInterceptor">
             org.jboss.test.hibernate.SimpleInterceptor</attribute>
          <attribute name="Hbm2ddlAuto">create</attribute>
    
          <depends>jboss:service=Naming</depends>
          <depends>jboss:service=TransactionManager</depends>
       </mbean>
    
    </server>
    

    is now

    <hibernate-configuration xmlns="urn:jboss:hibernate-deployer:1.0">
    
       <session-factory name="java:/hib-timers/SessionFactory" bean="jboss.test.har:service=Hibernate,testcase=TimersUnitTestCase">
          <property name="datasourceName">java:/DefaultDS</property>
          <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
          <property name="sessionFactoryInterceptor">org.jboss.test.hibernate.SimpleInterceptor</property>
          <property name="hbm2ddlAuto">create</property>
          <depends>jboss:service=Naming</depends>
          <depends>jboss:service=TransactionManager</depends>
       </session-factory>
    
    </hibernate-configuration>
    

     

    Name this file with -hibernate.xml suffix for JBossAS to automatically detect the configuration.

     

    You can additionally specify at which level you want your scanning for mappings to occur, see scanFromTop flag in HibernateDeployer (see deployers/hibernate-deployer-beans.xml).

     

    You can also directly include this new xml part in your -beans.xml, but then you must explicitly specify harUrl property.

     

     

     

    HAR Deployer

    A Hibernate ARchive (or HAR) includes all the resources needed to deploy a

    Hibernate MBean instances. The archive must end in a .har extension (it may

    be an exploded deployment) and contain:

     

    • a meta-inf/hibernate-service.xml which defines the Hibernate MBean for deployment.  Other MBeans may additionally be defined within the hibernate-service.xml; this may be useful, for example, to define a TreeCache MBean to be used as the second-level cache or the Hibernate3 statistics MBean.  Only one org.jboss.hibernate.jmx.Hibernate MBean may be defined within a given hibernate-service.xml descriptor.

    • the domain classes, maintaining package structure, as the HAR will be added to the deployment classpath.

    • the Hibernate mapping files, which can occur anywhere in the archive; two best practices here are to either bundle the mappings with the classes they map, or to have all the mappings in meta-inf.

    • <optionally> additional jar files to be added to the deployment classpath.

     

    Note: JBoss 4.0.2 will not load exploded hars.  There is a bug logged in Jira for it: http://jira.jboss.com/jira/browse/JBAS-1801

     

    When a HAR is processed by the HAR Deployer, a Hibernate MBean instance is created based on the HAR's meta-inf/hibernate-service.xml and the contents of the har (the mappings are processed using Hibernate's Configuration.addJar() method).

     

    A HAR can be deployed stand-alone, nested within a SAR, or as part of an EAR. If included in an EAR, the EAR's meta-inf/jboss-app.xml must define the har as a module as such:

    <module>
       <har>har-file-name-relative-to-ear-root.har</har>
    </module>
    

    Note the new <har/> module type used to denote the HAR subdeployment.

     

    Note (since JBoss 4.0.3): From JBAS-2000 http://jira.jboss.com/jira/browse/JBAS-2000#action_12321886: because '.har' deployments are now processed by the SARDeployer, this forces the deployment descriptor to be renamed from hibernate-service.xml to jboss-service.xml

     

    Hibernate3+JBoss4.2.x issue

    I found one issue.

     

     

    Session Management

     

    All applications using Hibernate need to deal with the questions relating to the lifecycle of the Sessions they obtain from the SessionFactory.  When should the session be opened; how should components throughout the application obtain the "current" session; how should flushing and closing of the session be handled?

     

    The most common usage pattern for Hibernate in J2EE applications running within an application server is to use the app server DataSource and TransactionManager capabilities.  Typically a session is opened at the beginning of a "request"

    and closed at the end of that "request", and in between the session is bound to the "current context" to be accessible to application components.  See the Hibernate wiki for an explanation of the well-known session management use-cases.

     

    Since version 3.0.1, Hibernate itself has the ability to track the "current session" and to expose that to applications through the getCurrentSession() method of the SessionFactory.  If the given SessionFactory has already bound a session to the "current context", then sucessive calls to getCurrentSession() will continue to return the same session; if not, a new Session is generated, bound to the "current context", and then returned.

     

    So what constitutes the "current context" for these managed session?  The transaction!  Internally, the ~SessionFactory tracks the current sessions by the transaction in which they were first requested.  A javax.transaction.Synchronization is registered with that transaction so that Hibernate can manage the flushing/closing of these managed sessions automatically.

     

    One caveat to note here is that due to the use of the Transaction to scope or track the current session, the JTA transaction must be started prior to the session initially being bound.

     

    For those familiar with (or using) the Hibernate2-based integration, the HibernateContext class has been ported forward to help ease migration.  However, it has been deprecated and its use is not recommended.  See the javadocs for HibernateContext for appropriate replacement calls.

     

    DeployedTreeCacheProvider

     

    (This feature was removed in AS 5; see CacheManager integration below for the replacement.)

     

    As mentioned previously, the org.jboss.hibernate.cache.DeployedTreeCacheProvider

    allows users to deploy a JBossCache TreeCache as a service itself, and use that

    deployed service as the second-level cache for the Hibernate SessionFactory.

    See JBossCache for documentation on deploying JBossCache as a service.

     

    Assuming we have a JBossCache instance deployed with the ObjectName "jboss.har:service=HarSecondLevelCache", then configuring the

    org.jboss.hibernate.jmx.Hibernate MBean to use that instance as the second level cache would look something like:

     

    <mbean name="jboss.har:service=Hibernate" code="org.jboss.hibernate.jmx.Hibernate">
      <depends>jboss:service=Naming</depends>
      <depends>jboss:service=TransactionManager</depends>
      <depends>jboss.har:service=HarSecondLevelCache</depends>
      <!-- our other mbean attributes -->
      <attribute name="CacheProviderClass">org.jboss.hibernate.cache.DeployedTreeCacheProvider</attribute>
      <attribute name="DeployedTreeCacheObjectName">jboss.har:service=HarSecondLevelCache</attribute>
    </mbean>
    

     

    or, even:

    <mbean name="jboss.har:service=Hibernate" code="org.jboss.hibernate.jmx.Hibernate">
      <depends>jboss:service=Naming</depends>
      <depends>jboss:service=TransactionManager</depends>
      <depends optional-attribute-name="DeployedTreeCacheObjectName">jboss.har:service=HarSecondLevelCache</depends>
      <!-- our other mbean attributes -->
      <attribute name="CacheProviderClass">org.jboss.hibernate.cache.DeployedTreeCacheProvider</attribute>
    </mbean>
    

     

     

    CacheManager Integration

     

    In JBoss AS 5, the DeployedTreeCacheProvider discussed above was removed and replaced by an integration based on Hibernate 3.3's new RegionFactory second level caching SPI and the AS 5 CacheManager service.

     

    Assuming we have a JBossCache instance deployed with the ObjectName "jboss.har:service=HarSecondLevelCache" and bound into JNDI under the name "java:HarSecondLevelCache", then configuring the org.jboss.hibernate.jmx.Hibernate MBean to use that instance as the second level cache would look something like:

     

    <mbean name="jboss.har:service=Hibernate" code="org.jboss.hibernate.jmx.Hibernate">
      <depends>jboss:service=Naming</depends>
      <depends>jboss:service=TransactionManager</depends>
      <depends>jboss.har:service=HarSecondLevelCache</depends>
      <!-- our other mbean attributes -->
      <attribute name="CacheRegionFactoryClass">org.hibernate.cache.jbc2.JndiSharedCacheRegionFactory</attribute>
      <attribute name="DeployedCacheJndiName">java:HarSecondLevelCache</attribute>
    </mbean>
    

     

    To configure the Hibernate MBean to use the CacheManager service (bound by default into JNDI under "java:CacheManager") as the source of its cache, use this configuration:

     

    <mbean name="jboss.har:service=Hibernate" code="org.jboss.hibernate.jmx.Hibernate">
      <depends>jboss:service=Naming</depends>
      <depends>jboss:service=TransactionManager</depends>
      <!-- our other mbean attributes -->
      <attribute name="CacheRegionFactoryClass">org.hibernate.cache.jbc2.JndiMultiplexedCacheRegionFactory</attribute>
      <attribute name="DeployedCacheManagerJndiName">java:CacheManager</attribute>
    </mbean>

     

    For complete details on Hibernate 3.3's integration with JBoss Cache, see the Using JBoss Cache 2 as a Hibernate Second Level Cache reference manual.

     

    Bundling other versions of Hibernate3

    TODO (at least Hibernate 3.0.1 required); should be as simple as bundling the version

    you want to use within the HAR and utilizing a loader-repository, but this needs

    to be tested.

     

    Hibernate2 vs. Hibernate3

    See the switching doc regarding switching versions of

    Hibernate used in the integration.

     

    Hibernate 3.1 + JBoss 4.0.3

    For the layer of dominion of Hibernate 3 (or later) in JBoss 4.0.3, only the package .har is required and the respective DataSource, since deployer for hibernate (to jboss-hibernate.deployer) it comes integrated, in fact also includes libraries necessary.

     

    Logging Hibernate-SQL, values and transaction events

     

    You can modify the the log4j.xml-File and add the following categories:

     

       <!-- Limit the org.hibernate category to INFO since logging to DEBUG affects performance badly -->
       <category name="org.hibernate">
          <priority value="INFO"></priority>
       </category>
       
       <!-- Log SQL statements-->
       <category name="org.hibernate.SQL">
          <priority value="DEBUG"></priority>
       </category>
        
       <!-- Log the values assigned to the SQL parameters and results -->
       <category name="org.hibernate.type">
          <priority value="DEBUG"></priority>
       </category>
    
       <!-- Log transaction event/JTA -->
       <category name="org.hibernate.transaction">
          <priority value="DEBUG"></priority>
       </category>
       <category name="org.hibernate.event.def.AbstractFlushingEventListener">
          <priority value="DEBUG"></priority>
       </category>
    
       <!-- Show SQL Logs for Hibernate Schema Export -->
       <category name="org.hibernate.tool.hbm2ddl.SchemaExport">
          <priority value="DEBUG" ></priority>
       </category>     
    

     

    You can comment out all the information you do not want logged. Logging really costs performance in this case. You should be aware that by default the DEBUG level is only logged to the server.log file. For console output you need to lower the console threshold from INFO to DEBUG.