mercoledì 12 dicembre 2007

Seam Spring and connections lost

Using high level frameworks as seam and spring, you think you are safe from dangerous things like loosing open connections to your db .... but it happened.
I don't know why yet, but using spring transactions with seam and an hibernate transaction manager my webapp was eating connections, expecially when starting (and not ending) long running conversations. Reload many times the page with @Begin and my webapp was lost.
My solution was to switch to JTA, and it was really simple when:

1) found the right hint at to choose the right JTA implementation for my postgresDB (that for now is not in the supported list of BTM, I hope for the better ;-) );
2) read BTM article to configure it in spring;
3) downloaded latest jdbc driver for postgres, with a must have fix.

you have to configure hibernate.connection.release_mode to after_statement (with JTA) beacause Spring changes default to on_close, and long running conversations keep the hibernate session open (and hopefully disconnected from db connection).
Moreover, as written in Seam docs, set hibernate.transaction.flush_before_completion to true, so to flush the session before commit of surrounding transaction.

<!-- I have this in my hibernate.cfg.xml -->
<property name="hibernate.connection.release_mode">after_statement</property>
<property name="hibernate.transaction.flush_before_completion">true</property>

Spring's application.xml:

<bean id="dataSource" class="" init-method="init" destroy-method="close">
<property name="className" value="org.postgresql.xa.PGXADataSource" />
<property name="uniqueName" value="pgsql" />
<property name="minPoolSize" value="0" />
<property name="maxPoolSize" value="${db.maxActive}" />
<property name="driverProperties">
<prop key="databaseName">ibusiness_web</prop>
<prop key="user">${db.user}</prop>
<prop key="password">${db.pwd}</prop>

<!-- Bitronix Transaction Manager embedded configuration -->
<bean id="btmConfig" factory-method="getConfiguration" class="">
<property name="serverId" value="spring-btm" />

<!-- create BTM transaction manager -->
<bean id="BitronixTransactionManager" factory-method="getTransactionManager"
class="" depends-on="btmConfig,dataSource" destroy-method="shutdown" />

<bean id="sessionFactory"
<property name="dataSource">
<ref local="dataSource" />
<property name="configLocation" value="/WEB-INF/classes/hibernate.cfg.xml" />

<bean id="seamSessionFactory" class="org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean">
<property name="sessionName" value="hibernateSession"/>

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="seamSessionFactory" />

<!-- Spring JtaTransactionManager -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />

Seam's components.xml:

<persistence:managed-hibernate-session name="hibernateSession" auto-create="true" session-factory="#{sessionFactory}"/>
<spring:spring-transaction platform-transaction-manager="#{transactionManager}"/>
<spring:context-loader config-locations="/WEB-INF/application.xml"/>

NOTE: in application.xml use as reference for other beans seamSessionFactory as the only sessionFactory. sessionFactory is defined in Spring only to be wrapped by Seam in components.xml.

Thanks to spring, I didn't change a line of code, and very few of xml.
Thanks to seam, now I can leverage its long running conversations to improve my app.

Thanks to google and all of you who share their good and bad experiences, so I do now.

1 commento:

Kristina ha detto...

Good for people to know.