Er, no, I didn't have to tinker with any JTA stuff.
I figured it out after a great deal of googling, translating from Russian and Chinese.
You'd think someone would have a solution posted years ago, oh well.
Assume you have two databases, Olaf and Sven. they can be live in the same instance of a database server or be in different instances on different physical machines.
I set up my project in Eclipse, with packages of "urproject.dao", "urproject.dao.hibernate", "urproject.model" and "urproject.persistance".
All my mapping files go in "urproject.model" regardless of which database the corresponding tables reside in. So, Car.java maps to table Cars, etc, as expected.
I use annotations and DAOs so expect to make some adjustments if you do not.
Olaf contains tables:
-- Animals
-- Cars
-- Trees
Sven contains tables:
-- Plants
-- Planes
-- Flowers
Step 1You'll need to create
ONE cfg.xml file PER DATABASE, with the connection parameters pointing to the proper places. These files go in the directory where the
defalt hibernate.cfg.xml used to reside - I deleted mine.
so,
olaf.cfg.xml
Code:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.username">trickydicknixon</property>
<property name="connection.password">xxxxxx</property>
<property name="connection.url">jdbc:mysql://localhost:3306/olaf</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.autocommit">false</property>
<property name="current_session_context_class">thread</property>
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">600</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">400</property>
<property name="hibernate.show_sql">false</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!--<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property> -->
<mapping class="urproject.model.Animal"/>
<mapping class="urproject.model.Car"/>
<mapping class="urproject.model.Tree"/>
</session-factory>
</hibernate-configuration
sven.cfg.xml
Code:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.username">lyndonbjohnson</property>
<property name="connection.password">yyyyyyyy</property>
<property name="connection.url">jdbc:mysql://localhost:3306/sven</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.autocommit">false</property>
<property name="current_session_context_class">thread</property>
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">600</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">400</property>
<property name="hibernate.show_sql">false</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!--<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property> -->
<mapping class="urproject.model.Plant"/>
<mapping class="urproject.model.Plane"/>
<mapping class="urproject.model.Flower"/>
</session-factory>
</hibernate-configuration
You'll have to set up the username/password/connection stuff to suit your needs.
Step 2In each of your dao.hibernate files you'll need to make adjustments to all your getSession statements to tell them which session to grab:
For example, in CarDAOHibernate.java you'd change
public List<Car> getAll()
{
List<Car> results = null;
String sqlcmd;
sqlcmd = " FROM Car ";
/* Query hqlQuery = getSession().createQuery( sqlcmd); <-- old */
Query hqlQuery = getSession("olaf").createQuery( sqlcmd); // <-- new
results = hqlQuery.list();
return results;
}
Step 3Upgrade your GenericHibernateDAO.java by replacing the original getSession method
with the following:
Code:
/* original method
protected Session getSession() {
if( session == null)
session = HibernateUtil.getSessionFactory().getCurrentSession();
return session;
}
*/
// new methods
protected Session getSession() {
if( session == null)
session = HibernateUtil.currentSession();
return session;
}
protected Session getSession( String keyy) {
if( session == null)
session = HibernateUtil.currentSession( keyy);
return session;
}
Step 4Replace your HibernateUtil.java file with something like this:
Code:
package urproject.persistence;
import org.hibernate.*;
import org.hibernate.cfg.*;
import org.apache.commons.logging.*;
import javax.naming.*;
import java.io.*;
import java.util.*;
import java.net.URL;
public class HibernateUtil
{
private static final boolean usingAnnotations = true;
private static Log log = LogFactory.getLog(HibernateUtil.class);
private static HashMap<String, SessionFactory> sessionFactoryMap = new HashMap<String, SessionFactory>();
public static final ThreadLocal sessionMapsThreadLocal = new ThreadLocal();
static {
try {
String fileName;
SessionFactory sf;
// Create the SessionFactory objects from *.cfg.xml
ArrayList<String> cfglist = getHibernateCfgFiles("/");
for( String keyy : cfglist) {
fileName = keyy + ".cfg.xml";
if( usingAnnotations) {
sf = new AnnotationConfiguration().configure(fileName).buildSessionFactory();
} else {
sf = new Configuration().configure(fileName).buildSessionFactory();
}
sessionFactoryMap.put(keyy, sf);
}
} catch (Exception ex) {
ex.printStackTrace(System.out);
log.error("Initial SessionFactory creation failed.", ex);
System.out.println("Initial SessionFactories creation failed.");
throw new ExceptionInInitializerError(ex);
} // end of the try - catch block
}
public static Session currentSession() throws HibernateException
{
return currentSession("");
}
public static Session currentSession( String keyy) throws HibernateException
{
HashMap<String, Session> sessionMaps = (HashMap<String, Session>) sessionMapsThreadLocal.get();
if( sessionMaps == null) {
sessionMaps = new HashMap();
sessionMapsThreadLocal.set( sessionMaps);
}
// Open a new Session, if this Thread has none yet
Session s = (Session) sessionMaps.get(keyy);
if( s == null) {
s = ((SessionFactory) sessionFactoryMap.get(keyy)).openSession();
sessionMaps.put(keyy, s);
}
return s;
}
public static ArrayList<String> getHibernateCfgFiles( String path)
{
ArrayList<String> ret_arry = new ArrayList<String>();
String fileName, keyy;
String[] str_arry;
URL url = Configuration.class.getResource( path);
File file = new File( url.getFile());
if( file.isDirectory()) {
for( File f : file.listFiles()) {
if( f.isFile()) {
fileName = f.getName();
if( fileName.endsWith(".cfg.xml")) {
str_arry = fileName.split("\\.");
keyy = str_arry[0];
ret_arry.add( keyy);
}
}
}
}
return ret_arry;
}
public static void closeSession()
{
log.debug("closing a single session");
HashMap<String, Session> sessionMaps = (HashMap<String, Session>) sessionMapsThreadLocal.get();
sessionMapsThreadLocal.set(null);
if( sessionMaps != null) {
Session session = sessionMaps.get("");
if( session != null && session.isOpen())
session.close();
}
}
public static void closeSessions() throws HibernateException
{
log.debug("closing sessions");
HashMap<String, Session> sessionMaps = (HashMap<String, Session>) sessionMapsThreadLocal.get();
sessionMapsThreadLocal.set(null);
if( sessionMaps != null) {
for( Session session : sessionMaps.values()) {
if( session.isOpen())
session.close();
};
}
}
/**
* Closes the current SessionFactory and releases all resources.
* <p>
* The only other method that can be called on HibernateUtil
* after this one is rebuildSessionFactory(Configuration).
*/
public static void shutdown()
{
log.debug("Shutting down Hibernate");
closeSessions();
// Close caches and connection pools
if( sessionFactoryMap != null) {
for( SessionFactory sf : sessionFactoryMap.values()) {
sf.close();
}
}
sessionFactoryMap = null; // Clear static variables
}
}
YMMV. No doubt someone wiser than I can improve upon the above code, but this works for me.
CASE CLOSED
Thank for reading,
Still-learning Steve