Migrate Hibernate managed C3P0 Pool to Spring Managed - java

I'm Spring(yfying) my application that uses Hibernate + C3P0 for the connection pool. I'm using a managed hibernate context for specific reasons. I'm using a utility class "HibernateUtil" for Session handling. For the first migration to Spring I am creating an ApplicationContext and retrieving a SessionFactory bean in HibernateUtil replacing the code that used to build the SessionFactory. When I create a session factory bean completely from my old hibernate.cfg.xml in Spring everything works as expected:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:config/hibernate.cfg.xml"></property>
</bean>
hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="connection.username">user</property>
<property name="connection.url">jdbc:mysql://localhost:3306/mydb?zeroDateTimeBehavior=convertToNull</property>
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="connection.password">pass</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.max_fetch_depth">3</property>
<property name="hibernate.current_session_context_class">org.hibernate.context.ManagedSessionContext</property>
<property name="hibernate.transaction.auto_close_session">false</property>
<property name="hibernate.cache.region.factory_class">
net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.show_sql">true</property>
<property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
<!-- configuration pool via c3p0-->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="connection.isolation">2</property>
<property name="hibernate.c3p0.acquire_increment">3</property>
<property name="hibernate.c3p0.idle_test_period">120</property> <!-- seconds -->
<property name="hibernate.c3p0.max_size">100</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.min_size">3</property>
<property name="hibernate.c3p0.timeout">1800</property>
<!-- mapping files -->
.......
If I externalize the connection pool (I also remove all the connection settings from hibernate.cfg.xml), my transactions do not work properly.
<bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driver}"/>
<property name="jdbcUrl" value="${db.url}"/>
<property name="user" value="${db.user}"/>
<property name="password" value="${db.pass}"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="configLocation" value="classpath:config/hibernate.cfg.xml"></property>
</bean>
I've tried specifying hibernate.transaction.factory_class and moving hibernate properties to Spring bean configuration instead of using hibernate.cfg.xml all to no avail. I cannot completely switch to Spring Transaction management just yet.

Imho you should try to move everything to Spring. In my experience when it is to mixed up there are a lot of problems. Is there a particular reason why you cannot yet set up a spring managed transaction management using:
<!-- Transaction Management -->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
From your description it is quite dificult to find out where exactly the problem is occuring is it with the transactions or with the sessionFactory?
Another point you might be causing your sessionFactory problems when using the dataSource outside of the hibernateProperties is that the ConnectionProvider implementation Hibernate is using is changing. If you specify a dataSource Hibernate will use DataSourceConnectionProvider(http://docs.jboss.org/hibernate/orm/3.6/javadocs/org/hibernate/connection/DatasourceConnectionProvider.html) whereas with setting the data source in the hibernate config Hibernate will use the DriverManagerConnectionProvider (http://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/connection/DriverManagerConnectionProvider.html)
The differences between these two might be the cause of your problems.

Related

Entity manager has not been injected

I just started working with Spring ROO and I generated my entity classes using the database reverse engineer command. However whenever I try to call one of the CRUD method in the generated entity class, I keep getting this exception :
java.lang.IllegalStateException: Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)
I suspect(by looking at the generated files) that the EntityManager was not injected into the class. Please could you tell me what configuration I am missing?
Here is what my applicationContext.xml looks like
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
<context:spring-configured/>
<context:component-scan base-package="com.lennartz">
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1 FROM DUAL"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
And the generated entity files
privileged aspect UserDetail_Roo_Jpa_ActiveRecord {
#PersistenceContext
transient EntityManager UserDetail.entityManager;
public static final EntityManager UserDetail.entityManager() {
EntityManager em = new UserDetail().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return em;
}
Please let me know if there is something I'm missing.
You must not modify the .aj files, to customize the Roo generated code read http://docs.spring.io/spring-roo/docs/2.0.0.M1/reference/html/#edit-modify-and-customize-the-roo-generated-code
I eventually figured out the problem, it seems context was not being initialized in my application.
I added the following line in my web.xml and it worked
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
If your application is not a web app, I assume initializing the context using ClassPathXmlApplicationContext should work for you.

Issue while setting up spring annotation based transactions

I have an application which used mix of JPA and JDBC. I have successfully done setup for JPA transaction using #Transactional annotation, but I am not able to make it work for JDBC.
My configuration looks like:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
My code is :
#Test
#Transactional
public void testUpdateSQLwithParam() {
Object[] params = { "John","", "trol", "test", "M", "Place", "123456789",
"tom#domain.com" };
customQueryDao.insert("PERSON_INSERT_QUERY", params);
String sqlConstant = "PERSON_MASTER_UPADTE_QUERY";
params = new Object[]{ "Test", 8 };
customQueryDao.updateSQLwithParam(sqlConstant, params);
}
My JDBC code uses jdbcTemplate to execute queries. Please let me know how I can have JDBC transactions using #Transactional annotation. using jpatransactionmgr
You have 2 beans defined with the same id (transactionManager). Try it with a different ID, maybe like:
<bean id="jPATransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
This should work, you can also enable debugging on log4j to see transactions in your log files, here's what I have in my log4j.xml:
<!-- 3rdparty Loggers -->
<logger name="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<level value="debug" />
</logger>
I can see from you edit that you tried to fix the problem of multiple transaction manager. But I think you did not remove the good one ... From javadoc of JpaTransactionManager : This transaction manager also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource).
IMHO you should instead keep the JpaTransactionManager, and remove the DataSourceTransactionManager. (I have some code using plain JDBC mixed with Hibernate access with a single HibernateTransactionManager and transaction are correctly managed ...)

After implementing C3P0 the page keeps refreshing

I am trying to implement C3P0 into my hibernate. I have as follows:
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://IPaddress</property>
<property name="hibernate.connection.username">user</property>
<property name="hibernate.connection.password">password</property>
<property name="hibernate.current_session_context_class">thread</property>
<!-- JDBC connection pool (use the built-in) -->
<!--<property name="connection.pool_size">20</property>-->
<property name="hibernate.c3p0.acquire_increment">1</property>
<property name="hibernate.c3p0.idle_test_period">1000</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.max_statements">10</property>
<property name="hibernate.c3p0.min_size">10</property>
<property name="hibernate.c3p0.timeout">864000</property>
<property name="hibernate.c3p0.idleConnectionTestPeriod">30</property>
<property name="hibernate.c3p0.initialPoolSize">10</property>
<property name="hibernate.c3p0.maxPoolSize">100</property>
<property name="hibernate.c3p0.minPoolSize">10</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Mappings -->
<mapping class="com.nebuilder.ats.pojo.TopicsDetails"/>
<mapping class="com.nebuilder.ats.pojo.GroupsDetails"/>
<mapping class="com.nebuilder.ats.pojo.ModulesDetails"/>
<mapping class="com.nebuilder.ats.pojo.TraineesDetails"/>
<mapping class="com.nebuilder.ats.pojo.ColoursDetails"/>
<mapping class="com.nebuilder.ats.pojo.CustomersDetails"/>
<mapping class="com.nebuilder.ats.dao.MusicStoreDaoImpl"/>
</session-factory>
</hibernate-configuration>
ApplicationContext.xml
<beans>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:jdbc.properties"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"
p:connectionProperties="${jdbc.connectionProperties}"/>
<!-- ADD PERSISTENCE SUPPORT HERE (jpa, hibernate, etc) -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
</beans>
Both of the files are in my resources folder. They seem to be working, but the problem is that my page keeps loading or refreshing without displaying any information when I try to access the database.
I am using jars as follow - hibernate-c3p0 3.6.3.Final, hibernate-core 3.6.3.Final, c3p0 0.9.1.2
Did you try to debug your application to see where is the problem ?
Moreover, it seems to be a little bit excessive to define a timeout of 864 000 ms, isn't it ?

Spring+hibernate vs hibernate configuration. Cause of UnsupportedOperationException: Not supported by BasicDataSource

Initially I used only hibernate
And I had following hibernate.cfg.xml:
<hibernate-configuration>
<session-factory>
<property name="hbm2ddl.auto">create</property>
<property name="connection.url">jdbc:mysql://localhost:3306/...</property>
<property name="connection.username">root</property>
<property name="connection.password">XXX</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="connection.pool_size">1</property>
<property name="current_session_context_class">thread</property>
//mapping
...
</session-factory>
</hibernate-configuration>
And It works good:
after I include Spring and then configuration look so:
...
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/..." />
<property name="username" value="root" />
<property name="password" value=XXX />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
...
after it I see in console:
java.lang.UnsupportedOperationException: Not supported by BasicDataSource
at org.apache.commons.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1432)
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:139)
After I tried to remove
<property name="connection.username">root</property>
<property name="connection.password">XXX</property>
from hibernate.cfg.xml and I don't see exceptions.
Can you explain what is the cause of this problems?
Initially I thought that problem that I shouldn't duplicate information in different configurations but now I see that for example url define inside dataSource and inside hibernate.cfg.xml
Please clarify this Spring + Hibernate magic.
Be aware that with:
org.springframework.jdbc.datasource.DriverManagerDataSource
You're not provided with connection pooling!
I would recommend to move to Tomcat JDBC Connection Pool.
That is by now IMHO the most efficient one.
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
It requires the dependency
org.apache.tomcat tomcat-jdbc
Check documentation:
https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html
I had the same problem. The BasicDataSource class will connect using its own url, username and password parameters. Session factory will use already configured data source. Therefore as a result the url, username and password parameters are overridden. Just ditch those connection parameters in hibernate.cfg.xml because they are managed by the dataSource bean.
I had this same issue and after above solution I got a destroy method 'close' not found error or something along those lines.
However, it does appear that getConnection(user, password) is the underlying issue here. When I commented out the connection.username and connection.password in the hibernate.cfg.xml everything works fine.
Correction: I should clarify that I moved the user name and password to the appContext like so
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://127.0.0.1:3306/my_schema"
p:username="root"
p:password="mypassword">
</bean>
In latest version getConnection(User,Password) method is not supported.
It will helps you :
Replace
org.apache.commons.dbcp2.BasicDataSource
with
org.springframework.jdbc.datasource.DriverManagerDataSource

name attribute in bean for sessionFactory is in 'red' in IDEA i.e. cannot resolve property

My app-config.xml looks like:
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--<property name="configLocation" value="classpath:hibernate.cfg.xml"/> -->
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.url=jdbc:mysql://localhost/mydb
hibernate.connection.username=devuser
hibernate.connection.password=devpwd
hibernate.query.substitutions=true 'Y', false 'N'
hibernate.cache.use_query_cache=true
hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.jdbc.batch_size=0
</value>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="userDao" class="com.blah.core.db.hibernate.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
the line
What could the reason be?
I loaded this in Intellij Idea and saw no red for name attributes, including uncommenting the configLocation property.
You probably want to check that you've got the correct versions of the libraries configured in Intellij, as the name attribute appears to be not matching fields in library classes, particularly the AnnotationSessionFactoryBean that you're using.

Categories

Resources