lazy loading entities in spring with jpa and hibernate - java

I'm using Spring with JPA and Hibernate. I've got some DAO-Classes that are annotated with #Repositoy and some Controller-Classes. When I call one of the dao's methods in my controller to load some entities I get back the Entity and after that, I want to get some other entities that are stored in a field of the first loaded entity. But at that time spring has already closed the session and lazy loading is no longer possible.
My db.xml configuration:
<?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:mvc="http://www.springframework.org/schema/mvc"
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-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/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.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd" default-autowire="byName">
<!-- Scans within the base package of the application for #Components to configure as beans -->
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:db.properties" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="jpaVendorAdapter" />
</bean> -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="${db.dialect}" />
</bean>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />
</beans>
The method in the Dao is annotated as follows:
#Transactional(readOnly = true, propagation=Propagation.REQUIRED)
now I wanna do something like this:
#Controller
public class HomeController{
#Autowired
private UserDao userDao;
#RequestMapping(value = "/", method = RequestMethod.GET)
public ResponseEntity<String> home(){
...
User user = userDao.findUser(id);
Set<Order> orders = user.getOrders();
...
String myResult = ...;
return jsonService.generateResponse(myResult);
}
}
#Repository
public class UserDao{
#PersistenceContext
private EntityManager entityManager;
public User findUser(Integer id){
return entityManager.find(User.class, id);
}
}
The set of orders should be lazy-loaded but i get the following exception: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:...,no session or session was closed
root cause: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ..., no session or session was closed
I tried to annotate the method in Controller wirt #Transactional and also to set mode="aspectj" in annotation-driven property in the db.xml, but nothing did work. Is there any way to lazy load the orders of the user?
For any help, thanking you in anticipation!

You can use special filter to get session in web view. Add to your web.xml
<filter>
<filter-name>jpaFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>jpaFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
the filter works as follows:
The filter intercepts a servlet request
The filter opens an EntityManager and binds it to the current thread
Web controller is called
Web controller calls service
Transaction interceptor begins a
new transaction, retrieves the thread-bound EntityManager and binds
it to the transaction
Service is called, does some stuff with
EntityManager, then returns
Transaction interceptor flushes the
EntityManager then commits the transaction
Web controller prepares
view, then returns
View is built
Filter closes the EntityManager and
unbinds it from current thread

Related

How to solve org.springframework.beans.factory.BeanNotOfRequiredTypeException error in Spring MVC

I am new in Spring. I have tried a demo project with Spring MVC, Hibernate, Spring-tx and Spring ORM. There I am facing the error. My scenario is:
public interface DaoInterface{
public SessionFactory getSessionFactory();
public Session getSession();
}
Another class BaseDao:
public abstract class BaseDao implements DaoInterface{
#Autowired
private SessionFactory sessionFactory;
private Session session;
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
public Session getSession() {
this.session = sessionFactory.getCurrentSession();
return this.session;
}
public abstract User retriveUser(String email);
}
Another class UserDao:
#Component
public class UserDao extends BaseDao{
#Override
#Transactional
public User retriveUser(String email) {
System.out.println("In userDao : retriveUser");
//other code
}
}
Now from my service class, when I am going to get UserDao object using BaseDao, I got the error:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'userDao' is expected to be of type 'dao.BaseDao' but was actually of type 'com.sun.proxy.$Proxy94'
My service class code:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BaseDao userDao = context.getBean("userDao", BaseDao.class);
If I do the following, no error comes.
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DaoInterface userDao = context.getBean("userDao", DaoInterface.class);
My applicationContext.xml is as below:
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="model" />
<context:component-scan base-package="dao" />
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="abcDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/demo"></property>
<property name="user" value="xxxx"></property>
<property name="password" value="xxxxx"></property>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="maxIdleTime" value="30000" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="abcDataSource" />
<property name="packagesToScan" value="model" />
<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="abcTransactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="abcTransactionManager" />
</beans>
So, my question is, what need to be done in my application, so that I can get UserDao object using BaseDao class reference, not DaoInterface reference?
Some answers are there in this platform, but I am not getting the exact answer. Few solutions I have tried but can't solve.
Spring uses JDK dynamic proxies by default ($Proxy94), that can only proxy interfaces. That's basically why you can cast the userDao bean to the Dao interface, but not to the BaseDao class.
By the way you should prefer coding by interfaces.
However You can use <tx:annotation-driven proxy-target-class="true"/> to instruct Spring to use CGLIB proxies.

#Transactional don't work, maybe bad configuration for sessionfactory.getCurrentSession() [duplicate]

I'm getting the above exception with Spring3 and Hibernte4
The following is my bean xml file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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
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.1.xsd">
<context:annotation-config/>
<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/GHS"/>
<property name="username" value="root"/>
<property name="password" value="newpwd"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.example.ghs.model.timetable</value>
</list>
</property>
</bean>
<bean id="baseDAO"
class="com.example.ghs.dao.BaseDAOImpl"/>
</beans>
My BaseDAO class looks like this
public class BaseDAOImpl implements BaseDAO{
private SessionFactory sessionFactory;
#Autowired
public BaseDAOImpl(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
#Override
public Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
}
The following code throws the exception in the title
public class Main {
public static void main(String[] args){
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("dao-beans.xml");
BaseDAO bd = (BaseDAO) context.getBean("baseDAO");
bd.getCurrentSession();
}
}
Does anyone have an idea about how to solve this problem?
getCurrentSession() only makes sense inside a scope of transaction.
You need to declare an appropriate transaction manager, demarcate boundaries of transaction and perform data access inside it. For example, as follows:
<bean id = "transactionManager" class = "org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
.
PlatformTransactionManager ptm = context.getBean(PlatformTransactionManager.class);
TransactionTemplate tx = new TransactionTemplate(ptm);
tx.execute(new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(TransactionStatus status) {
// Perform data access here
}
});
See also:
10. Transaction Management
13.3 Hibernate
I came across same problem and got solved as below
Added #Transactional on daoImpl class
Added trnsaction manager in configuration file:
<tx:annotation-driven/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
I'll just add something that took me some time to debug : don't forget that a #Transactional annotation will only work on "public" methods.
I put some #Transactional on "protected" ones and got this error.
Hope it helps :)
http://docs.spring.io/spring/docs/3.1.0.M2/spring-framework-reference/html/transaction.html
Method visibility and #Transactional
When using proxies, you should apply the #Transactional annotation
only to methods with public visibility. If you do annotate protected,
private or package-visible methods with the #Transactional annotation,
no error is raised, but the annotated method does not exhibit the
configured transactional settings. Consider the use of AspectJ (see
below) if you need to annotate non-public methods.
Which package u have put the BaseDAOImpl class in.. I think It requires a package name similar to the one u have used in the application context xml and it requires a relevant annotation too.

Spring mvc + hibernate/jpa -> entity manager is not injected despite #PersistenceContext

I have a problem with EntityManager. When I try to use EntityManager in a dao class, I got null pointer exception. So EntityManager is not injected despite #PersistenceContext annotation.
My dao:
package com.fido.pia.dao;
import com.fido.pia.model.User;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Repository
public class UserDao {
#PersistenceContext
protected EntityManager entityManager;
public User save(User row) {
if(row.isNew()) {
entityManager.persist(row);
return row;
} else {
return entityManager.merge(row);
}
}
}
Servlet Config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--
Adds some default beans (HandlerAdapter, HandlerMapping, Binding Initializer...). It also turn on some annotations.
Explanation in http://stackoverflow.com/questions/28851306/spring-framework-what-is-the-purpose-of-mvcannotation-driven
WITHOUT THIS, #RequestMapping ANNOTATIONS ARE LOADED, BUT MAPPING DO NOT WORK!!
-->
<mvc:annotation-driven />
<!-- Set loading annotations from classes
<context:component-scan base-package="com.fido.pia"/>-->
<!--manual homepage-->
<mvc:view-controller path="/" view-name="home"/>
<!--view resolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
<!--static resources - request will be handeled by ResourceHttpRequestHandler-->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!--database config-->
<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/pia" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<!--entity manager factory-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.fido.pia" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!--<property name="generateDdl" value="true" />-->
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<!-- Transactions -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!--Set loading annotations from classes-->
<context:component-scan base-package="com.fido.pia"/>
</beans>
Any ideas what is wrong here?
In entityManagerFactory bean definition, try this :
<property name="packagesToScan" value="com.fido.pia.*" />
This should work
I finally solve it. The problem was that I use common dependency injection to inject my dao class in controller. When I change it to DI with autowired (added #autowired to controller constructor), entity manager in dao is initialized.
So now it works, but I'm still curious about why is that change so important. I've asked new question about it.
You need to enable persistence annotations:
<context:annotation-config/>
or
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

how to rollback in entitymanager createNativeMethod

I am using native method of entity manager and I want to rollback when some error occurs.For this I tried #Transactional annotation but this does not rollback.Below is my sample code
controller
#Autowired
ServiceImpl ServiceImpl;
#RequestMapping("/saveinfo")
#ResponseBody
#Transactional
public String saveinfo(Long id)
{
ServiceImpl.saveInfo(id);
}
Service class
#Autowired
DAOImpl daoImpl;
#Transactional
public String saveinfo(Long id)
{
daoImpl.saveInfo1(id);
daoImpl.saveInfo12(id);
daoImpl.saveInfo12(id);
}
DAO class
#Override
public BigInteger saveInfo11() {
Query query = entityManagerUtil.entityManager().createNativeQuery("insert query");
return (BigInteger)query.getSingleResult();
}
#Override
public BigInteger saveInfo12() {
Query query = entityManagerUtil.entityManager().createNativeQuery("insert query");
return (BigInteger)query.getSingleResult();
}
#Override
public BigInteger saveInfo13() {
Query query = entityManagerUtil.entityManager().createNativeQuery("insert query");
return (BigInteger)query.getSingleResult();
}
Now in the above codes,
If I have some runtime error in saveInfo3() then I want to rollback methods of
saveInfo1() and saveInfo2()
This is the way I did but it did not rollback,so Please tell me how to do
EDIT
I tried using
#Transactional(rollbackFor=MyException.class,propagation = Propagation.REQUIRED) and #Transactional(propagation = Propagation.REQUIRED) and
#Transactional(rollbackFor=MyException.class))
In all the 3 cases ,it did not rollback
Update
applicationcontext.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
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/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-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/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<!--<context:annotation-config />-->
<context:spring-configured/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="persistenceUnit"/>
</bean>
<bean id="messageDigestPasswordEncoder" class="org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder">
<constructor-arg value="SHA-256" />
</bean>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" 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}"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<context:property-placeholder location="classpath*:META-INF/database.properties"/>
<context:property-placeholder location="classpath*:META-INF/project.properties"/>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="propertiesUtil" class="com.work.project.utils.PropertiesUtil">
<property name="locations" >
<list>
<value>classpath*:META-INF/*.properties</value>
</list>
</property>
</bean>
<context:component-scan base-package="com.work.project">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<task:executor id="myexecutor" pool-size="5" />
<task:annotation-driven executor="myexecutor"/>
</beans>
modified controller method
#Autowired
ServiceImpl ServiceImpl;
#RequestMapping("/saveinfo")
#ResponseBody
//Now I dont use transactional annotation in controller class
public String saveinfo(Long id)
{
ServiceImpl.saveInfo(id);
}
If any more information is required please ask
The problem seems to be that the EntityManager is not injected by Spring. The EntityManager instance is created by your utility class entityManagerUtil.entityManager(). This means, that everytime when you use a new EntityManager, they are not part of your method transaction.
In order to solve this problem: let Spring inject correctly the EntityManager (try for example injecting it directly in your original bean with #PersistenceContext and do those three methods directly in the same single method).
UPDATE:
The problem was that the code that threw the exception was in a try/catch block, this way, the transaction was not rolled-back by Spring. Transaction is rolled-back only when the transactional method exits with an RuntimeException (by default).
You need to change your method to have rollbackFor property for your #Transactional annotation, so that
#Transactional(rollbackFor=MyException.class)
public String saveinfo(Long id)
Keep in mind, that MyException should be unchecked exception, as checked exceptions thrown from #Transactional method will not result transaction to be rolled back.
Update:
To make sure everything is correct
Check that Spring indeed creates proxy and your method is being executed in transaction (e.g. use TransactionSynchronizationManager.isActualTransactionActive())
Check that MyException.class is indeed unchecked exception (subclass of java.lang.RuntimeException or java.lang.Error)
Check that your exception is indeed thrown (e.g. not catched somehow)
And why your controller saveInfo() is marked as transactional? This it not recommended, only service layer should be marked as transactional. See this post for example.
Maybe the entityManagerUtil (which you use within your DAO implementation) uses or creates an entity manager, that is not running in the surrounding transaction context. Please have a look at following tutorial: Here the JPA EntityManager is injected with #PersistenceContext
Can you make sure that your persistenceUnit has configured the following, transaction type(optional) and hibernate.connection.autocommit to false, if not please do so.
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<properties>
<property name="hibernate.connection.autocommit" value="false" />
</properties>
</persistence-unit>
I have excluded other properties for brevity

Cannot inject sessionFactory

While trying to get sessionFactory.getCurrentSession() debugger shows that sessionFactory is null. I assume Spring 3 fails to inject sessionFactory into this class although all configuration seems to be in place. How to fix it?
ServiceOrderDAO:
#Transactional
public class ServiceOrderDAO{
#Autowired
static
SessionFactory sessionFactory;
public static List<ServiceOrderEntity> search(params...){
Session localSession = sessionFactory.getCurrentSession();
...
}
}
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config />
<mvc:annotation-driven/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="" />
<property name="suffix" value=".jsp" />
</bean>
<context:component-scan base-package="controller" />
<context:component-scan base-package="dao" />
<context:component-scan base-package="service" />
<context:property-placeholder location="classpath:dbConnection.properties" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="model" />
</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"/>-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.pass}" />
</bean>
<bean id="jdbcTemplateBean" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
There are a few things I think you'll want to touch up:
SessionFactory shouldn't be static, nor should your search method be static if you're trying to treat that class as a Spring bean.
Add a #Component or #Repository annotation to the class. I don't think Spring will autowire classes that are missing a stereotype annotation on the class.
You should consider moving your #Transactional annotation to the method so you can provide more fine-grained propagation. For example, your search method may not require a transaction so you may want to use #Transactional(propagation = Propagation.SUPPORTS). Check out the Spring documentation for additional info that explains the various annotations and where/how to annotate transactions.
sessionFactory being static definitely is the cause of the problem. You can't inject static fields with spring.
Going under the covers, the static fields gets initialized by classloader, before the constructor gets called, and therefore before spring gets chance to inject anything.
And your service class should be transactional, not your dao. And yes you need to annotate with #Component or #Service or similar.

Categories