Hibernate-Spring Web container error - spring

Hello I'm new to Hibernate.
I have generated with Hibernate Tools a database access module. The generator generates the code of the DAOS and Hibernate Beans.
When I test this module in a simple Java application all works fine, but when I test it in a Spring Web application I get a very strange error. Since my module is an independent jar it should access the database without regarding the circumstance of being executed in a simple Java application or a Web application. The code of my web application is:
#Controller
#RequestMapping("/")
public class Controller implements ApplicationContextAware
{
private ApplicationContext applicationContext;
#RequestMapping(value = "/purchased/songs", method = RequestMethod.GET)
public String home(Model model)
{
SessionManager.startOperation();
ChargeTryDAOBase ctdb=new ChargeTryDAOBase();
List <ChargeTry> data=ctdb.findByRemoteId("dsfsdfsdf8");
SessionManager.endOperation();
model.addAttribute("result", "data" );
return "home";
}
#Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException
{
this.applicationContext = arg0;
}
}
When running this code on Tomcat I get following error:
org.springframework.web.util.NestedServletException: Handler processing
nested exception is java.lang.NoSuchMethodError:
org.hibernate.SessionFactory.getCurrentSession()Lorg/hibernate/Session;
.....
java.lang.NoSuchMethodError:
org.hibernate.SessionFactory.getCurrentSession()Lorg/hibernate/Session;
When I change some Hibernate dependencies I get following error:
java.lang.IllegalStateException: Could not locate SessionFactory in JNDI
When I test the above code in a simple Java application all works fine.
Is this a spring-hibernate configuration problem?
Thank you for your help.

Please study
1: http://www.javatpoint.com/hibernate-and-spring-integration
and
2 http://viralpatel.net/blogs/spring3-mvc-hibernate-maven-tutorial-eclipse-example/
to get insight of Spring MVC and Hibernate Integration.
You can work with Hibernate Configuration file - here is the link -
Spring and hibernate.cfg.xml
But as your application is within a spring managed container, We will highly recommend to use applicationcontext.xml for better maintenance and management of codebase and performance.

thank you for your help finally I got all working. I followed your link and googled a little bit. The problem was that I didn't enable in my hibernate.cfg.xml file the datasource parameter, I also have configured C3P0 jdbc connection provider.
My final hibernate.cfg.xml file is:
<hibernate-configuration>
<session-factory>
<property name="hibernate.bytecode.use_reflection_optimizer">true</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mydb</property>
<property name="hibernate.connection.username">userdb</property>
<property name="hibernate.connection.password">12345</property>
<property name="hibernate.connection.datasource">java:comp/env/jdbc/mydb</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.use_sql_comments">true</property>
<property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">2</property>
<property name="hibernate.c3p0.numHelperThreads">4</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">1800</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<hibernate-configuration>
<session-factory>
In my web.xml I have added following lines:
<resource-ref>
<description>This is a MySQL database connection</description>
<res-ref-name>jdbc/mydb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
In the Spring context file I have added following lines:
<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<beans:property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<beans:property name="username" value="userdb"/>
<beans:property name="password" value="12345"/>
</beans:bean>
<beans:bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="configLocation">
<beans:value>classpath:hibernate.cfg.xml</beans:value>
</beans:property>
</beans:bean>
The strange thing is, that with the default Hibernate connection provider, the above solution didn't work but when I configured C3P0 all started to work.
Thank you for your help.

Related

How to configure multiple MyBatis datasources in Spring Boot?

With MyBatis-Spring-Boot-Starter, we can easily integrate MyBatis with Spring Boot, it works perfectly for one data source. However, now we'd like to add an extra data source in our project, unfortunately it seems not easy.
In MyBatis official documentation, I see the following content:
MyBatis-Spring-Boot-Starter will:
Autodetect an existing DataSource.
Will create and register an instance of a SqlSessionFactoryBean passing that DataSource as an input.
Will create and register an instance of a SqlSessionTemplate got out of the SqlSessionFactoryBean.
It looks like MyBatis-Spring-Boot-Starter supports only one data source at this moment. So, the question is how to configure multiple MyBatis datasources in Sping Boot?
You outlined 3 beans that are needed for MyBatis+Spring integration. These are automatically created for single data source.
If you need two data sources, you need to create 3 beans for each data source explicitly. So you'll be creating 6 beans (2 of type DataSource, 2 of type SqlSessionFactoryBean and 2 of type SqlSessionFactoryBean).
To bind DAO with certain datasource, you will need to use sqlSessionTemplateRef or sqlSessionFactoryRef parameter of #MapperScan annotation.
Also I don't recommend to go down the XML hell. I was using it this way in PROD, with two data sources, without any ugly XML configs on various projects. Also SQL queries were annotated.
Shame is that MyBatis documentation is not great and most examples out there are in XML.
Something this like this to your spring servlet.xml:
<bean id="db2dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>${db2.database.driver}</value></property>
<property name="url"><value>${db2.database.url}</value></property>
<property name="username"><value>${db2.database.username}</value></property>
<property name="password"><value>${db2.database.password}</value></property>
<property name="maxActive"><value>${db2.database.maxactiveconnections}</value></property>
<property name="maxIdle"><value>${db2.database.idleconnections}</value></property>
<property name="initialSize"><value>${db2.database.initialSize}</value></property>
</bean>
<bean id="db2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="db2dataSource" />
<property name="configLocation" value="/WEB-INF/mybatis-config.xml"/>
</bean>
<bean id="db2Dao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="db2SqlSessionFactory"/>
<property name="mapperInterface" value="com.dao.db2Dao" />
</bean>
<bean id="oracledataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>${oracle.database.driver}</value></property>
<property name="url"><value>${oracle.database.url}</value></property>
<property name="username"><value>${oracle.database.username}</value></property>
<property name="password"><value>${oracle.database.password}</value></property>
<property name="maxActive"><value>${oracle.database.maxactiveconnections}</value></property>
<property name="maxIdle"><value>${oracle.database.idleconnections}</value></property>
<property name="initialSize"><value>${oracle.database.initialSize}</value></property>
</bean>
<bean id="oracleSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="oracledataSource" />
<property name="configLocation" value="/WEB-INF/mybatis-config.xml"/>
</bean>
<bean id="oracleoardDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="oracleSqlSessionFactory"/>
<property name="mapperInterface" value="com.lodige.clcs.dao.oracleoardDao" />
</bean>
Maybe this is what you need
#Configuration
#MapperScan(basePackages = "com.neo.mapper.test1", sqlSessionTemplateRef =
"test1SqlSessionTemplate")
public class DataSource1Config {
#Bean(name = "test1DataSource")
#ConfigurationProperties(prefix = "spring.datasource.test1")
#Primary
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "test1SqlSessionFactory")
#Primary
public SqlSessionFactory testSqlSessionFactory(#Qualifier("test1DataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
#Bean(name = "test1TransactionManager")
#Primary
public DataSourceTransactionManager testTransactionManager(#Qualifier("test1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
#Bean(name = "test1SqlSessionTemplate")
#Primary
public SqlSessionTemplate testSqlSessionTemplate(#Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}

Is JTA manager necessary to use transaction features in hibernate 4

I'm following the tutorial here:
http://www.javacodegeeks.com/2013/05/hibernate-4-with-spring.html
to enable the "#Transactional annotation" in my Java web application but failed to make it run properly. Please advise if the JTA manager is really required, and why?
Please note that my webapp is based on Spring 3 + Hibernate 4 + Tomcat 7.
Background and my doubts:
My current web application uses my own custom class (implements HandlerInterceptor) to enable one-hibernatesession-per-request basis. Now I want to improve my application's maintainability by using the "#Transactional annotation" instead since that could save many lines of code.
According to my understanding, the #Transactional basically relies on the AOP concept to ensure the session (Hibernate session) is ready for use in the annotated method. This seems nothing to do with the JTA. But I wonder why can't I make it work on my webapp in Tomcat 7 (without JTA-provider).
After few searches on google, it looks like the JTA is required. This confuses me since this seems to be a very basic functionality that shouldn't have the complicated JTA-provider as a requirement.
Here is the error I got:
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:988)
...
This is the code I use for testing:
....
#Autowired
org.hibernate.SessionFactory sessionFactory;
#Transactional
#RequestMapping(method = RequestMethod.GET)
protected String home() {
Session session = sessionFactory.getCurrentSession(); // I expected the session is good to use now
Province p = (Province) session.get(Province.class, 1L); // This causes no session found error :(
return "home";
}
The spring XML:
....
<tx:annotation-driven/>
<context:component-scan base-package="..."/>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/..."/>
<property name="lookupOnStartup" value="true"/>
<property name="proxyInterface" value="javax.sql.DataSource"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
....
Thank you !
Just a speculation:
Your controller is defined in some kind of dispatcher-servlet.xml therefore seperates from the applicationContext in which < tx:annotation-driven/> is defined. The compoment you want to enhance with #Transactional need to be within the same context with < tx:annotation-driven> if I'm not mistaken. So the #Transactional does not work.
That was my silly mistake. The Spring uses CGLIB to proxy methods with #Transactional annotated and it seems like CBLIB can't enhance protected method.
protected String home() {
Changing this to
public String home() {
fixed the problem.

EntityManager.flush() not flushing (JPA2 (OpenJPA), EJB3, Spring3, Websphere 7)

I'm facing a problem in my project: entityManager.flush() is not doing anything, and the flushing is only being done right before commit, when exiting the EJB.
My project runs on WebSphere 7.
I'm using JPA2 through OpenJPA.
I'm using Spring for Autowiring.
I'm using Container Managed Transactions.
Relevant code snippets below
persistence.xml
<persistence-unit name="persistenceUnit" transaction-type="JTA">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<properties>
<property name="openjpa.TransactionMode" value="managed" />
<property name="openjpa.ConnectionFactoryMode" value="managed" />
<property name="openjpa.DynamicEnhancementAgent" value="true" />
<property name="openjpa.jdbc.DBDictionary" value="StoreCharsAsNumbers=false" />
<property name="openjpa.Log" value="SQL=TRACE"/>
</properties>
</persistence-unit>
applicationContext.xml
<!-- Configure a JPA vendor adapter -->
<bean id="openJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
<!-- Entity Manager -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/myappDS"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="openJpaVendorAdapter" />
</bean>
EJB3 Bean
#Stateless(name="JPABaseEntityServiceBean")
#Configurable
public class JPABaseEntityServiceBean implements JPABaseEntityService {
Logger logger = LoggerFactory.getLogger(JPABaseEntityServiceBean.class);
#Autowired
JPABaseEntityDao jpaBaseEntityDao;
public JPABaseEntity persist(JPABaseEntity jpaBaseEntity) {
return jpaBaseEntityDao.persist(jpaBaseEntity);
}
DAO:
#Repository
public class JPABaseEntityDao implements BaseEntityDao {
#PersistenceContext
transient EntityManager entityManager;
public JPABaseEntity persist(JPABaseEntity jpaBaseEntity) {
Date now = new Date();
jpaBaseEntity.setCreatedBy(TO_DO_ME);
jpaBaseEntity.setUpdatedBy(TO_DO_ME);
jpaBaseEntity.setUpdatedOn(now);
jpaBaseEntity.setCreatedOn(now);
entityManager.persist(jpaBaseEntity);
entityManager.flush();
return jpaBaseEntity;
}
The "INSERT" is being done only when leaving the EJB, meaning the entityManager.flush() inside the DAO is not working
Ok, resolved in a way
Seems like the problem was that the Entity Manager was not getting the Transaction from WebSphere (probably because the Entity Manager was being injected by Spring, I haven't investigated that deeply)
So what I did is make Spring control the transaction in the EntityManager:
1. added <tx:annotation-driven/> and <tx:jta-transaction-manager/> to applicationContext.xml
2. annotated the DAO methods with #Transactional
The overall transaction is still handled by the EJB, meaning it's still using CMT and JTA from WebSphere
I had a ton of problems in the way because of dependency hell (the one that got me the most was hibernate-core including JBoss's javax.transaction implementation, grr), but other than that everything seems to be working smoothly

spring mvc and jdbc

I am beginning with spring and I am working on the web mvc. When not in MVC, as pointed in some tutorial, I would specify the data source in beans.xml and call this file with ApplicationContext object, and creating an object by passing the data source. And that worked for me. and when I came back to MVC, I created the data source in my name-servlet.xml file by using
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/hello"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
and I have a superclass used for my service classes for data access, only with method setDataSource. and here is my sample.
#Resource(name="dataSource")
public void setDataSource(DataSource dataSource){
this.dataSource=dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
but I am still getting a null pointer exception when working with the dataSource. please what am i missing?

Spring testing framework - JNDI resource

I am toying a bit with Spring testing framework, but I have one problem. Normally when application is deployed on Tomcat we have
<Resource
name="jdbc/sqliteDS"
auth="Container"
type="javax.sql.DataSource"
maxActive="4"
maxIdle="2"
username="x"
maxWait="5000"
driverClassName="org.sqlite.JDBC"
password="x"
url="jdbc:sqlite:/home/xxx/db.sqlite"/>
</Context>
in Tomcat context.xml,
<resource-ref>
<description>sqlite DataSource</description>
<res-ref-name>jdbc/sqliteDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
in web.xml and
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/comp/env/jdbc/sqliteDS" />
</bean>
in data-context.xml
for getting data source, but how can I emulate JNDI resource for Spring test framework, because now during the initialization I am getting errors that data source is not found, and he is right.
Also, it would be great if one can do that without writing another .xml file.
I had to deal with this question a while ago, and I didn't find a suitable solution, but a workaroud which implies another xml file :
First you create a Spring configuration file defining your JNDI infos (jndi.xml) :
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#server:port:instance" />
<property name="username" value="user" />
<property name="password" value="pwd" />
</bean>
</beans>
Then a static class to bind your JNDI variable :
public class Initialize {
public static void initializeJndi() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("jndi.xml");
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind("java:comp/env/jdbc/foo", applicationContext.getBean("dataSource"));
builder.activate();
}
}
Then in your test class, you add the following :
#BeforeClass
public static void initJndi() throws Exception {
Initialize.initializeJndi();
}
So that when you load your Spring main configuration file, the JNDI resource is accessible.
Maybe this is not the best way to do it but it surely works.
By the way, having a specific configuration file seems to be a good idea because you may not want to run your unit test on the final database. Doing so is more considered as integration testing than unit testing.
Hope it helps,
Mouwah

Resources