--- On Mon, 7/20/09, David Smith <d...@cornell.edu> wrote:

> From: David Smith <d...@cornell.edu>
> Subject: Re: Seeking the right solution to java.lang.ClassNotFoundException: 
> com.mysql.jdbc.Driver
> To: "Tomcat Users List" <users@tomcat.apache.org>
> Date: Monday, July 20, 2009, 6:16 PM
> Caldarale, Charles R wrote:
> >> From: David Smith [mailto:d...@cornell.edu]
> >> Subject: Re: Seeking the right solution to
> >> java.lang.ClassNotFoundException:
> com.mysql.jdbc.Driver
> >>
> >> This configuration is using a tomcat managed
> database pool.  Put your
> >> mysql jar file in tomcat's lib folder and you'll
> see the error go away.
> >>     
> >
> > But the stated intent is to use C3P0 pooling, rather
> than Tomcat's pooling; in that case, the <Resource>
> element must be removed and instead configured via whatever
> mechanism C3P0 wants.  Can't have both.
> >
> >  - Chuck
> >
> >
> >   
> No argument here.  I'm just diagnosing the current
> issue.  If the OP
> wants help with C3PO, that should be the configuration we
> are given.
> 
> --David

Late to the thread, and this is probably overkill.

This is my understanding concerning how the Tomcat / Hibernate / database 
environment works.  Your mileage may vary, and I will probably be corrected by 
some people on the list.

Please note that I've only used Tomcat managed database pooling.

Tomcat Managed Database Pooling
===============================

Anyway, here is my environment.

OS      - Fedora 10
===================
jdk/jre   - 1.6.0_14
Tomcat    - 6.0.20
MySQL     - 5.0.77-1
IDE       - NetBeans 6.7
Hibernate - 3.2.5.ga (provided with NetBeans)

OS        - Windows/XP Professional SP 3
===================
jdk/jre   - 1.6.0_14
Tomcat    - 6.0.20
MySQL     - 5.1.31
IDE       - NetBeans 6.7
Hibernate - 3.2.5.ga (provided with NetBeans)

I've chosen to use Tomcat's database pooling for the NetBeans DVD Store 
tutorial sample application.  This necessitates several changes in how the 
application is configured.

Basics
======

1. Per Tomcat documentation, I've placed
   mysql-connector-java-5.0.8-bin.jar in Tomcat's lib directory.  This
   makes it available to Tomcat in order to set up database pooling

2. All Hibernate jars are located in WEB-INF/lib.  NetBeans builds the
   war file correctly, so I don't have to copy any jar files around.

Web Application
===============

This also follows the Tomcat documentation for creating Tomcat-managed
connection pooling.

1. In META-INF/context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/DVDStore">
    <Resource auth="Container"
              driverClassName="com.mysql.jdbc.Driver"
              maxActive="30" maxIdle="10"
              maxWait="10000" name="jdbc/sakila"
              password="*****"
              type="javax.sql.DataSource"
              url="jdbc:mysql://localhost/sakila"
              username="*****"/>
</Context>

Obviously, replace the asterisks with the appropriate username and
password.  Replace the database url with your appropriate database.

2. In WEB-INF/web.xml:

<resource-ref>
    <description>This is a MySQL database connection</description>
    <res-ref-name>jdbc/sakila</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

Hibernate Configuration
=======================

So far, this has all been more or less boilerplate Tomcat
configuration.  The next step is to get Hibernate to talk to Tomcat's
database connection pool as opposed to its own connection pool or a
direct connection.

After searching a bit on the Internet, I found that the following
connection information works.

1. In hibernate.cfg.xml located in WEB-INF/:

<!-- using container-managed JNDI -->
<propertyname="hibernate.connection.datasource">
    java:comp/env/jdbc/sakila
</property>

Note that jdbc/sakila matches the web.xml resource-ref-name, which
matches the name attribute in context.xml.  java:comp/env/ is the
namespace to look up the jdbc reference.

No other connection or pooling information should be present in your
hibernate.cfg.xml file.

Application Code

================

Since Hibernate hides a lot of the details for connection management,
this code should not have to change.  In particular:

1. Creating the SessionFactory

// SessionFactory from standard hibernate.cfg.xml file

try {
    sessionFactory =
        new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Log the exception. 
    log.fatal("Initial SessionFactory creation failed.", ex);
    throw new ExceptionInInitializerError(ex);
}

2. Getting the SessionFactory

public static SessionFactory getSessionFactory() {
    return sessionFactory;
}

For my application, both of these code snippets live in
HibernateUtil.java.  My code also creates an mbean for monitoring
Hibernate.

You can then wrap this code up in a servlet context listener, which
should then create the session factory (which connects to the Tomcat -
provided connection pool) at application startup.  It's also handy for
cleaning up resources when the application is shut down.  In my case,
I use this to unregister the monitoring mbean.

Other Notes
===========

If you look at your logs, you may see the following warning:

INFO SessionFactoryObjectFactory:82 -
     Not binding factory to JNDI, no JNDI name configured

This is due to the fact that Hibernate can bind a session factory to a
JNDI name, but none is configured.  This is not the JDBC resource.
This facility probably exists to make sharing session factories
easier, and to clean up calls like the following:

Session session = HibernateUtil.getSessionFactory().openSession();

Tomcat provides a read-only InitialContext, while Hibernate requires
read-write.  Tomcat is apparently following the specification for
unmanaged containers.  If you want to bind the session factory to a
JNDI object, you'll either have to move to a managed server
(Glassfish, JBoss, etc.), or search on the Internet for some posted
work-arounds.

The recommendation from the Hibernate documentation is to just leave
out the hibernate.session_factory_name property when working with
Tomcat to not try binding to JNDI.


Hibernate Managed Database Pooling
==================================

I've not tried this, since I always rely on container managed database
connections.  However, after reading the documentation, I gather that
this is what needs to be done.

Web Application Configuration
=============================

1. Remove the <Resource></Resource> element from the context.xml
   file.  Tomcat is not going to be managing the database connection.

2. Remove the <resource-ref></resource-ref> element the web.xml file.
   Tomcat is not going to be managing the database connection.

Jar Files
=========

According to the Tomcat classloader documentation, Tomcat makes jar
files available to your application in the following order:

    * Bootstrap classes of your JVM
    * System class loader classses (described above)
    * /WEB-INF/classes of your web application
    * /WEB-INF/lib/*.jar of your web application
    * $CATALINA_HOME/lib
    * $CATALINA_HOME/lib/*.jar

In particular, the following two pieces of information should be
noted.

1. The jar files in lib/ are made available to both your application
   and to Tomcat.  Database connection jars are placed here if you
   will be relying on Tomcat to manage connection pooling.

2. In general, application-specific jars (such as Hibernate's
   connection pooling jars) should NOT be placed in the lib/ directory
   of Tomcat.

Based on the above, you'll need to place the MySQL connection jar in
your WEB-INF/lib directory.  Hibernate ships with the CP30 connection
pooling classes, so as long as the Hibernate jars are in your
WEB-INF/lib directory (which they should be), you'll be fine.

Hibernate Application Configuration
===================================

Since Hibernate will be managing both the connection and the database
pooling, you'll have to configure Hibernate with that information.

In hibernate.cfg.xml, you'll need both connection information and
connection pooling information.  Here are the snippets of that file

<!-- connection information -->
<property name="hibernate.connection.driver_class">
    com.mysql.jdbc.Driver
</property>
<property name="hibernate.connection.url">
    jdbc:mysql://localhost/sakila
</property>
<property name="hibernate.connection.username">******</property>
<property name="hibernate.connection.password">******</property>

<!-- database pooling information -->
<property name="connection_provider_class">
    org.hibernate.connection.CP30ConnectionProvider
</property>
<property name="c3p0.minPoolSize">
    5
</property>
<property name="c3p0.timeout">
    1000
</property>

There are probably other properties to configure, but that should get
things up and running.  As always, change the database properties to
reflect your particular application.

Summary
=======

Tomcat managed database connections:

1. Requires META-INF/context.xml information
2. Requires WEB-INF/web.xml information
3. Requires a simple JNDI configuration referencing the connection
4. Requires the MySQL connectors to be in $CATALINA_HOME/lib
5. Requires the Hibernate jars to be in WEB-INF/lib

Hibernate managed database connections:

1. Requires NO META-INF/context.xml information
2. Requires NO WEB-INF/web.xml information
3. Requires connection information to be in hibernate.cfg.xml
4. Requires pooling information to be in hibernate.cfg.xml
5. Requires MySQL connectors to be in WEB-INF/lib (ideally)
6. Requires the Hibernate jars to be in WEB-INF/lib

Hope this helps.

/mde/

PS - I just hacked together the Hibernate-controlled database connection / 
pooling on a freshly installed Tomcat 6.0.20.  It works as advertised.






---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to