It's my first time I'm using ComboPooledDataSource in hibernate, but there's something wrong with my configurations I think, so that when I call DAO to retrieve all data from database this returns me nothing.
GenView
#RequestMapping(value="/getHospitals.ajax")
public #ResponseBody Map<String,? extends Object> loadHospitals(){
HashMap<String, List<Hastaneler>> modelMap = new HashMap<String,List<Hastaneler>>();
modelMap.put("hastaneler", genBUS.getHospitals());
return modelMap;
}
GenBUS
#Service
#Transactional(isolation = Isolation.DEFAULT, readOnly = false, propagation = Propagation.REQUIRED)
public class GenBUS implements IGenBUS {
private Log log = LogFactory.getLog(GenBUS.class);
#Autowired
private SessionClientData scd;
#Autowired
private GenDAO genDAO;
private JdbcTemplate jdbcTemplate;
#Autowired
private ComboPooledDataSource comboPooledDataSource;
#PostConstruct
public void dataSource2JdbcTemplate() {
this.jdbcTemplate = new JdbcTemplate(comboPooledDataSource);
}
public GenDAO getGenDAO() {
return genDAO;
}
#Override
public List<User> getHospitals() {
return genDAO.loadAllObject(User.class);
}
GenDAO
#Repository
public class GenDAO extends BaseDAO{
private Log log = LogFactory.getLog(GenDAO.class);
#Autowired
private SessionClientData scd;
#Autowired
private ComboPooledDataSource comboPooledDataSource;
private JdbcTemplate jdbcTemplate;
#PostConstruct
public void dataSource2JdbcTemplate() {
this.jdbcTemplate = new JdbcTemplate(comboPooledDataSource);
}
#Autowired
public GenDAO(SessionFactory sessionFactory) {
logger.debug("GenDAO constructor is called !!!!!!!!");
System.out.println("genDaoooooooooooooooo.....");
setSessionFactory(sessionFactory);
}
BaseDAO
public class BaseDAO extends HibernateDaoSupport {
protected org.hibernate.impl.SessionFactoryImpl baseSessionFactory;
public<T> List<T> loadAllObject(Class<T> clazz) {
return (List<T>) getHibernateTemplate().loadAll(clazz);
}
dao.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="baseSessionFactory"/>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
<property name="location" value="classpath:/resources/test.properties"/>
</bean>
<bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${database.driverClass}"/>
<property name="jdbcUrl" value="${database.url}"/>
<property name="properties">
<props>
<prop key="user">${database.user}</prop>
<prop key="password">${database.password}</prop>
</props>
</property>
<!--<property name="user" value="${database.user}"/>
<property name="password" value="${database.password}"/> -->
<property name="maxPoolSize" value="50"/>
<property name="initialPoolSize" value="2"/>
<property name="minPoolSize" value="1"/>
<property name="maxStatements" value="200"/>
<property name="maxIdleTime" value="300"/>
<property name="acquireIncrement" value="10"/>
<property name="unreturnedConnectionTimeout" value="90"/>
<property name="maxConnectionAge" value="120"/>
</bean>
<bean id="baseSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="comboPooledDataSource"/>
<!-- <property name="entityInterceptor">
<bean class="generic.logging.AuditTrailInterceptor"/>
</property> -->
<property name="packagesToScan">
<list>
<value>model.GenUser</value>
<value>model.Hastaneler</value>
<value>model.Hastanelerim</value>
<value>model.User</value>
</list>
</property>
<property name="cacheProvider" ref="ehCacheProvider"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
<prop key="hibernate.max_fetch_depth">2</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.dialect">${database.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="current_session_context_class">thread</prop>
<!--<prop key="hibernate.hbm2ddl.auto">none</prop>-->
</props>
</property>
<!-- <property name="eventListeners">
<map>
<entry key="pre-insert"><bean class="generic.logging.HibernateAuditLogListener"/></entry>
<entry key="pre-delete"><bean class="generic.logging.HibernateAuditLogListener"/></entry>
<entry key="pre-update"><bean class="generic.logging.HibernateAuditLogListener"/></entry>
</map>
</property>-->
</bean>
<bean id="ehCacheProvider" class="org.hibernate.cache.EhCacheProvider"/>
</beans>
test.properties
database.url=jdbc:mysql://127.0.0.1:3306/acilservis
database.driverClass=com.mysql.jdbc.Driver
database.user=root
database.password=
database.dialect=org.hibernate.dialect.MySQLDialect
format_sql=true
show_sql=true
I'm using Mysql InnoDB as database engine... Any suggestions?
I've solved this by changing jdbcTemplate...I reconfigured it to use my sessionFactory, and that worked :)
Related
The exception that i have
javax.persistence.TransactionRequiredException: No transactional EntityManager available
org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:275)
com.sun.proxy.$Proxy25.persist(Unknown Source)
com.cnp.incident.dao.FluxEntreesDAO.ajouterFlux(FluxEntreesDAO.java:37)
com.cnp.incident.services.ServiceFluxEntrees.ajouterFlux(ServiceFluxEntrees.java:33)
com.cnp.incident.controller.CreationManuelleFluxEntreesSorties.creer(CreationManuelleFluxEntreesSorties.java:64)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root-context.xml
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"/>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:database.properties</value>
</list>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.cnp.incident"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- Unite de persistence -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.cnp.incident"/>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.dialect" value="${hibernate.dialect}"/>
<entry key="hibernate.query.factory_class" value="org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory"/>
<entry key="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl.auto}"/>
<!-- A utiliser pour faciliter le debug -->
<entry key="hibernate.show_sql" value="${hibernate.show_sql}"/>
<entry key="hibernate.format_sql" value="${hibernate.format_sql}"/>
<!-- activation cache d'entités et de query -->
</map>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<!-- on référence la datasource "lazy" -->
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
My DAO
package com.cnp.incident.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.springframework.stereotype.Repository;
import com.cnp.incident.entite.FluxEntrees;
#Repository
public class FluxEntreesDAO implements IfluxEntreesDAO {
#PersistenceContext
private EntityManager entityManager;
//implémentation de la methode listeFlux de la DAO
public List<FluxEntrees> listeFlux() {
final CriteriaBuilder lCriteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<FluxEntrees> lCriteriaQuery = lCriteriaBuilder.createQuery(FluxEntrees.class);
final Root<FluxEntrees> lRoot = lCriteriaQuery.from(FluxEntrees.class);
lCriteriaQuery.select(lRoot);
final TypedQuery<FluxEntrees> lTypedQuery = entityManager.createQuery(lCriteriaQuery);
return lTypedQuery.getResultList();
}
//methode d'ajout de flux en base de données
public void ajouterFlux(final FluxEntrees pFlux) {
entityManager.persist(pFlux);
}
}
My Service
package com.cnp.incident.services;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.cnp.incident.dao.IfluxEntreesDAO;
import com.cnp.incident.entite.FluxEntrees;
#Service
public class ServiceFluxEntrees implements IServiceFluxEntrees{
#Autowired
private IfluxEntreesDAO dao;
#Transactional(readOnly=true)
public List<FluxEntrees> listeFlux() {
return dao.listeFlux();
}
#Transactional
public void ajouterFlux(Date mois, Integer entree, Integer sorties, String type) {
final FluxEntrees fluxEntrees = new FluxEntrees();
fluxEntrees.setMois(mois);
fluxEntrees.setEntrees(entree);
fluxEntrees.setSorties(sorties);
fluxEntrees.setType(type);
dao.ajouterFlux(fluxEntrees);
}
}*
Try with these changes to your transaction manager configuration (I'll only list the parts that need to be changed):
<tx:annotation-driven transaction-manager="txManager"/>
...
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
I have mysql server in linux server. It contains 5 database for 5 different clients. so far, I have created 5 tomcat instances to deploy 5 war based on client and accessing database from servelet.xml file like below,
client1 instance war :
<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/client1" />
<property name="username" value="rootuser" />
<property name="password" value="pswd" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" >
<constructor-arg ref="dataSource"/>
</bean>
client2 instance war :
<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/client2" />
<property name="username" value="rootuser" />
<property name="password" value="pswd" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" >
<constructor-arg ref="dataSource"/>
</bean>
Config class :
public class JdbcRepository {
#Autowired
#Qualifier("jdbcTemplate")
protected JdbcTemplate jdbcTemplate;
#Autowired
#Qualifier("namedParameterJdbcTemplate")
protected NamedParameterJdbcTemplate namedParameterJdbcTemplate ;
#Autowired
#Qualifier("dataSource")
private DataSource dataSource; //mysqlSource;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
return namedParameterJdbcTemplate;
}
public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
jdbcTemplate = new JdbcTemplate(this.dataSource);
}
public Long findMemberIdByUserName(String username) {
try{
String sql = "SELECT userLoginId FROM user WHERE userName = ?";
Long id = jdbcTemplate.queryForObject(sql, new Object[]{username}, Long.class);
return id;
}
catch(Exception e){
return 0l;
}
}
But now I want to create single instance and deploy single war for all clients and access the database based on user login. Like below,
<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/{DBBasedOnLoginUser}" />
<property name="username" value="rootuser" />
<property name="password" value="pswd" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" >
<constructor-arg ref="dataSource"/>
</bean>
How to achieve this?
So, you want to communicate with different databases depending upon some condition.
Changing datasource connection url runtime
This is exactly what you need.
I am using POST MAN CLIENT of GOOGLE CHROME TO SEND articleName and articleId AS HEADER application/json.What things I needed to change in my controller and library as well as in my spring servlet.xml?My controller is as follows.
public class ArticleController {
#Autowired
private ArticleService articleService;
Article article = new Article();
Long articleId = article.getArticleId();
#RequestMapping(value = "/save", method = RequestMethod.POST)
public Article saveArticle(#ModelAttribute Article article,
BindingResult bindingresult) {
int a = articleService.addArticle(article);
if (a == 1) {
return new ModelAndView("success");
} else {
return new ModelAndView("error");
}
}
My Spring servlet is:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
<context:component-scan base-package="net.roseindia" />
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<mvc:annotation-driven />
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>net.roseindia.model.Article</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
Plz help me out....Thanks in advance.
I assume what you want is to return JSON easily from Spring.
To do that you need Jackson dependency:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.7.1</version>
</dependency>
When you have it,
you can annotate your method with #ResponseBody annotation just like this:
public #ResponseBody Article saveArticle(#ModelAttribute Article article,
BindingResult bindingresult) {
....
}
Such a method will return JSONified Article object in response.
I tried different configurations but to no effect. The error remained the same. Here the desired config taken from BoneCPs web site:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.2.RELEASE.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.2.RELEASE.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
">
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" autowire-candidate="" autowire="autodetect">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.connection.provider_class">com.jolbox.bonecp.provider.BoneCPConnectionProvider</prop>
<prop key="hibernate.connection.driver_class">org.postgresql.Driver</prop>
<prop key="hibernate.connection.url">jdbc:postgresql:MyDB</prop>
<prop key="hibernate.connection.username">postgres</prop>
<prop key="hibernate.connection.password">123456</prop>
<prop key="bonecp.idleMaxAge">240</prop>
<prop key="bonecp.idleConnectionTestPeriod">60</prop>
<prop key="bonecp.partitionCount">1</prop>
<prop key="bonecp.acquireIncrement">5</prop>
<prop key="bonecp.maxConnectionsPerPartition">60</prop>
<prop key="bonecp.minConnectionsPerPartition">5</prop>
<prop key="bonecp.statementsCacheSize">50</prop>
<prop key="bonecp.releaseHelperThreads">2</prop>
</props>
</property>
</bean>
<!--<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" /> -->
<bean id="AbstractHibernateDAO" abstract="true"
class="org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO"/>
<bean id="ChemicalStructureDAO" extends="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalStructureDAO"/>
<bean id="ChemicalCompoundDAO" extends="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalCompoundDAO"/>
</beans>
And code containing autowired session factory:
#Repository
public abstract class AbstractHibernateDAO< T extends Serializable> {
private final Class< T> clazz;
#Autowired
SessionFactory sessionFactory;
public AbstractHibernateDAO(final Class< T> clazzToSet){
this.clazz = clazzToSet;
}
public T getById(final Long id) {
Preconditions.checkArgument(id != null);
return (T) this.getCurrentSession().get(this.clazz, id);
}
public List< T> getAll() {
return this.getCurrentSession()
.createQuery("from " + this.clazz.getName()).list();
}
public void create(final T entity) {
Preconditions.checkNotNull(entity);
this.getCurrentSession().persist(entity);
}
public void update(final T entity) {
Preconditions.checkNotNull(entity);
this.getCurrentSession().merge(entity);
}
public void delete(final T entity) {
Preconditions.checkNotNull(entity);
this.getCurrentSession().delete(entity);
}
public void deleteById(final Long entityId) {
final T entity = this.getById(entityId);
Preconditions.checkState(entity != null);
this.delete(entity);
}
protected final Session getCurrentSession() {
return this.sessionFactory.getCurrentSession();
}
}
When trying to create a new entity (last line of snippet) I get an error:
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
ChemicalStructureDAO structureDAO = (ChemicalStructureDAO) context.getBean("ChemicalStructureDAO");
ChemicalStructure structure1 = new ChemicalStructure();
structure1.setStructureKey("c1ccccc1");
structure1.setStructureData("c1ccccc1");
structureDAO.create(structure1);
I'm getting a NullPointerException:
java.lang.NullPointerException
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.getCurrentSession(AbstractHibernateDAO.java:78)
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.create(AbstractHibernateDAO.java:54)
at org.bitbucket.myName.moleculedatabaseframework.App.main(App.java:32)
------------------------------------------------------------------------
Maybe I missunderstood what autowired means? I thought that that property will be set automatically. So I tried following:
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
SessionFactory sessionfactory = (SessionFactory)context.getBean("sessionFactory");
ChemicalStructureDAO structureDAO = (ChemicalStructureDAO) context.getBean("ChemicalStructureDAO");
structureDAO.setSessionFactory(sessionfactory);
ChemicalStructure structure1 = new ChemicalStructure();
structure1.setStructureKey("c1ccccc1");
structure1.setStructureData("c1ccccc1");
structureDAO.create(structure1);
This leads to following error:
Exception in thread "main" org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.getCurrentSession(AbstractHibernateDAO.java:78)
at org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO.create(AbstractHibernateDAO.java:54)
I looked at tons of tutorials but they all omit what seems the basic stuff to get things running, eg. ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); does not appear in any spring + hibernate tutorials. Can someone point me at a complete tutorial one that assumes I'm completely dumb and tells me every step required and has an application that actually runs when repeating the code? (yes getting pretty frustrated now. To be honest if I went plain jdbc I would have been up and running hours ago)
Now,how can I get this running? How does autowired work?
EDIT:
THE SOLUTION AS FOUND THROUGH THE HELP OF "Accepted Answer":
The new Spring configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
">
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" autowire="autodetect">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalStructure</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompound</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompoundComposition</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<!-- Spring bean configuration. Tell Spring to bounce off BoneCP -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource">
<ref local="mainDataSource" />
</property>
</bean>
<!-- BoneCP configuration -->
<bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="org.postgresql.Driver" />
<property name="jdbcUrl" value="jdbc:postgresql:MolDB" />
<property name="username" value="postgres"/>
<property name="password" value="123456"/>
<property name="idleConnectionTestPeriod" value="60"/>
<property name="idleMaxAge" value="240"/>
<property name="maxConnectionsPerPartition" value="60"/>
<property name="minConnectionsPerPartition" value="20"/>
<property name="partitionCount" value="3"/>
<property name="acquireIncrement" value="10"/>
<property name="statementsCacheSize" value="50"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<context:annotation-config />
<bean id="AbstractHibernateDAO" abstract="true"
class="org.bitbucket.myName.moleculedatabaseframework.dao.AbstractHibernateDAO"/>
<bean id="ChemicalStructureDAO" parent="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalStructureDAO"/>
<bean id="ChemicalCompoundDAO" parent="AbstractHibernateDAO"
class="org.bitbucket.myName.moleculedatabaseframework.dao.ChemicalCompoundDAO"/>
</beans>
I had to add
<context:annotation-config />
to the file and declare the annoted entity classes in sessionFactory configuration:
<property name="annotatedClasses">
<list>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalStructure</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompound</value>
<value>org.bitbucket.myName.moleculedatabaseframework.entityclasses.ChemicalCompoundComposition</value>
</list>
</property>
The I had to uncomment the transaction Manager part and because of that change the data source configuration as the one I used did not work (DataSource is required).
I also had to add
#Repository
#Transactional
public abstract class AbstractHibernateDAO< T extends Serializable> {
//code...
}
to AbstractHibernateDAO. I'm considering to write a blog post and make a link here. For anyone completley new to Spring and hibernate that would be very useful.
Do you have something like this in your spring xml?
<context:annotation-config />
<context:component-scan base-package="base.package" />
This scans for the classes that contains Annotations.
I am doing unit testing and I expect that all data committed to the MySQL database will be rolled back... but this isn't the case. The data is being committed, even though my log was showing that the rollback was happening. I've been wrestling with this for a couple days so my setup has changed quite a bit, here's my current setup.
LoginDAOTest.java:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"file:web/WEB-INF/applicationContext-test.xml", "file:web/WEB-INF/dispatcher-servlet-test.xml"})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class UserServiceTest {
private UserService userService;
#Test
public void should_return_true_when_user_is_logged_in ()
throws Exception
{
String[] usernames = {"a","b","c","d"};
for (String username : usernames)
{
userService.logUserIn(username);
assertThat(userService.isUserLoggedIn(username), is(equalTo(true)));
}
}
ApplicationContext-Text.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/******"/>
<property name="username" value="*****"/>
<property name="password" value="*****"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="userService" class="Service.UserService">
<property name="userDAO" ref="userDAO"/>
</bean>
<bean id="userDAO" class="DAO.UserDAO">
<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>/himapping/User.hbm.xml</value>
<value>/himapping/setup.hbm.xml</value>
<value>/himapping/UserHistory.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory"/>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
</beans>
I have been reading about the issue, and I've already checked to ensure that the MySQL database tables are setup to use InnoDB. Also I have been able to successfully implement rolling back of transactions outside of my testing suite. So this must be some sort of incorrect setup on my part.
Any help would be greatly appreciated :)
The problem turned out to be that the connection was auto-committing BEFORE the transaction could be rolled back. I had to change my dataSource bean to include a defaultAutoCommit property:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="Ecosim07"/>
<property name="defaultAutoCommit" value="false" />
</bean>
For me defaultAutoCommit and #Transactional didn't help. I had to change db type to InnoDB
Another way to fix your problem:
Instead of using:
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
, which creates a MyISAM table by default, hence not supporting transactions
Try using
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
, which creates InnoDB tables, and thus supports transactions.
This must be used
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#TestExecutionListeners({ TransactionalTestExecutionListener.class })
#Transactional
TransactionalTestExecutionListener contains isRollback() which rollbacks the
transaction after the test method.
I hope I am right and that this is a simple one. You are missing the #Transactional annotation on your test class. This means that the test method itself isn't run in a transaction and thus there is nothing to roll back. Hope this helps.