Poco tempo fa ho sviluppato un progetto web JSF(Java Server Faces) e Axis2 per il quale ho utilizzato Java, Tomcat e Mysql.
Ho avuto la necessita’ di ottenere un pool di connessioni, come framework di persistenza al data base ho utilizzato Hibernate, quindi, brevemente, cerco di descrivere i punti principali per ottenere questo risultato.
Livello:
Medio, Medio/Avanzato
Per chi:
Ha la necessita ottenere una connection pool tramite
l’utilizzo di Tomcat, MySql e Hibernate
I punti principali per ottenere un pool di connessioni sono il web.xml presente nella dir WEB-INF, il context.xml presente nella dir META-INF, l’ hibernate.cfg.xml che puo’ essere o nella root delle vostre classi o nella di WEB-INF e due oggetti necessari all’ottenimento della connessione.
Ora, in ordine, una descrizione per configurare in modo corretto tutti gli aspetti.
Nel web.xml e’ necessario aggiungere un nodo resource-ref in questo modo:
<resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/miodb</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
Il contenuto del elemento res-ref-name verra’ utilizzato per identificare la risorsa successivamente.
Nel context.xml aggiungiamo la seguente Resource:
<Resource name="jdbc/miodb"
global="jdbc/miodb"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="nonricordo"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/miodb?autoReconnect=true"
maxActive="50"
maxIdle="4"
validationQuery="Select 1"
/>Questo permette di mantenere un pool di connessioni sino ad un massimo di 50 con un massimo di 4 non attive, il ValidationQuery permette di validare la connessione.
E’ possibile impostare altri parametri ma per questo meglio fare riferimento alla documentazione che sicuramente e’ molto piu’ esaustiva ;)
Nell’ hibernate.cfg.xml le seguenti principali proprieta’:
<session-factory> <!-- dettagli connessione --> <property name="connection.datasource">java:comp/env/jdbc/miodb</property> <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property> <!-- Disabilita cache di secondo livello. --> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <property name="cache.use_query_cache">false</property> <property name="cache.use_minimal_puts">false</property> <property name="max_fetch_depth">3</property> <!-- cabla il metodo getCurrentSession() al thread. --> <property name="current_session_context_class">thread</property> <!-- dichiarazione dei modelli delle tabelle --> <mapping resource="it/crx/models/hibernate/Tabella.hbm.xml"/>
Come potete notare in questa configurazione NON vengono dichiarate le credenziali di accesso al database dato che vengono ereditate dal context.xml tramite l’indicazione della proprieta connection.datasource.
Non e’ stato usato il c3po dato che anche nella documentazione ufficiale ne sconsigliano l’utilizzo in ambienti di produzione.
Creiamo un oggetto “HibernateUtil”, reperibile ovunque in rete variante piu’ variante meno :), che servira per ottenere la connessione e i metodi transazionali necessari all’appicazione.
public class HibernateUtil { private static SessionFactory sessionFactory; public static Configuration getInitializedConfiguration() { return new Configuration().configure(); } static { try { // Crea la SessionFactory from hibernate.cfg.xml sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Make sure you log the exception, as it might be swallowed System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } public static Session getSession() { if (sessionFactory == null) { Configuration config = HibernateUtil.getInitializedConfiguration(); sessionFactory = config.buildSessionFactory(); } Session hibernateSession = sessionFactory.getCurrentSession(); return hibernateSession; } public static void closeSession() { HibernateUtil.getSession().close(); } public static void flushSession() { HibernateUtil.getSession().flush(); } public static Session beginTransaction() { Session hibernateSession; hibernateSession = HibernateUtil.getSession(); hibernateSession.beginTransaction(); return hibernateSession; } public static void commitTransaction() { HibernateUtil.getSession().getTransaction().commit(); } public static void rollbackTransaction() { HibernateUtil.getSession().getTransaction().rollback(); } public static void main(String args[]) { HibernateUtil.recreateDatabase(); } }
Ora creiamo un Listener per fare in modo che all’avvio della nostra webapp hibernate si “attacchi” al database e precarichi tutte le sue configurazioni necessarie:
public class HibernateListener implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { HibernateUtil.getSessionFactory(); } public void contextDestroyed(ServletContextEvent event) { HibernateUtil.getSessionFactory().close(); } }
Logicamente per fare in modo che il listener si attivi e’ necessario richiamarlo nel file web.xml in questo modo:
<listener> <listener-class>it.crx.core.hibernate.HibernateListener</listener-class> </listener>
A questo punto dovreste essere a posto, avviate la webapp e nei log dovreste vedere scorrere, tra gli altri, le INFO di hibernate.
Se non e’ stata generata nessuna eccezione guardando mysql dovreste vedere una connessione in sleep:
mysql> show processlist; +----+------+-----------------+----------+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------------+----------+---------+------+-------+------------------+ | 2 | root | localhost:36814 | miodb | Sleep | 4 | | NULL | | 3 | root | localhost | NULL | Query | 0 | NULL | show processlist | +----+------+-----------------+----------+---------+------+-------+------------------+ 2 rows in set (0.00 sec)
Ora, per fare un esempio, facciamo una select e un update di un record, cosi da vedere sia l’ottenimento di una sessiono normale sia quello di una transazionale.
Select che non interviene sui dati:
// otteniamo una sessione di lavoro Session hibernateSession = HibernateUtil.getSessionFactory().openSession(); // peleviamo un utente con l'id dal database User user = (User) hibernateSession.get(User.class, 123);
Update di un record:
// iniziamo la transazione Session hibernateSession = HibernateUtil.beginTransaction(); User user = (User) hibernateSession.get(User.class, 123); user.setEmail("123@example.com"); try { session.update(user); // eseguo la commit delle modifiche HibernateUtil.commitTransaction(); } catch (HibernateException e) { // qualche cosa e' andato storto, "storno" le richieste di modifica HibernateUtil.rollbackTransaction(); throw new MiaException("request failed - " + e.getMessage(), e); }
Note tecniche
Alcuni dettagli relativi alle librerie principali e versioni utilizzate nel progetto per il quale ho eseguito il setup della configurazione sopra descritta
- Java 1.6.0_11
- Tomcat 6.0.20
- Mysql 5.0.67
- hibernate3.jar
- mysql-connector-java-5.1.8-bin.jar
- axis2-1.5-bin.zip
- myfaces 1.2.7.jar e relative commons
- jstl e standard.jar
- richfaces 3.3.1
Il tutto perfettamente funzionante ;)
Nella solita speranza di essere d’aiuto per qualcuno che si trova a litigare con questo ambiente saluto tutti.
Ciao,
Cristian.
RSS feed for comments on this post · TrackBack URI
Leave a reply
You must be logged in to post a comment.