when I try to save an object I get write operations are not allowed.
Here is the code.
configuration for transaction manager
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate4.HibernateTemplate" >
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven />
Service Class
#Service
public class MemberDetailServiceImpl implements MemberDetailService {
#Autowired
private MemberDetailsDao memberDetailsDao;
#Transactional(readOnly = false)
public String saveExtraInfoMember(MemberActivity activity){
return memberDetailsDao.saveExtraInfoMember(activity);
}
Dao
#Repository
public class MemberDetailsDaoImpl implements MemberDetailsDao {
#Autowired
HibernateTemplate hibernateTemplate;
public String saveExtraInfoMember(MemberActivity activity) {
// TODO Auto-generated method stub
String result=null;
hibernateTemplate.saveOrUpdate(activity);
return "";
}
Related
We are working on a Tapestry5-Spring-Hibernate application.
We are using Tapestry 5.4.1, Spring 4.3.1.RELEASE and Hibernate 4.3.6.Final.
We are using and XML based application.
We are facing the problem that all daos #Autowired into spring services are always null. This will of course generate a NullpointerException everytime a dao is needed to perform an operation on the database.
We used generic service and dao interfaces
Here are the code samples:
Spring config file
<context:annotation-config />
<context:component-scan base-package="org.prism.forecast" />
<context:property-placeholder location="classpath:hibernate.properties" />
<!--Generic DAO -->
<bean id="appDao" primary="true" class="org.prism.forecast.dao.AppDaoImpl">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<!--Generic service-->
<bean id="appServiceImpl" class="org.prism.forecast.services.AppServiceImpl">
<property name="dao">
<ref bean="appDao" />
</property>
</bean>
<bean id="requestDao" class="org.prism.forecast.dao.RequestDaoImpl">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="requestServiceImpl" class="org.prism.forecast.services.RequestServiceImpl">
<property name="dao">
<ref bean="requestDao" />
</property>
</bean>
<bean id="SOPUploadDao" class="org.prism.forecast.dao.SOPUploadDaoImpl">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="SOPUploadServiceImpl" class="org.prism.forecast.services.SOPUploadServiceImpl">
<property name="dao">
<ref bean="SOPUploadDao" />
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.prism.forecast.entities" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"/>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
Generic DAO Interface
public interface AppDao {
/**
* Finds an object by id
*
* #param <T>
* #param <PK>
* #param type
* #param id
* #return the object
*/
<T, PK extends Serializable> T find(Class<T> type, PK id);
//other methods
}
Generic DAO implementation
#Repository("appDao")
public class AppDaoImpl implements AppDao {
protected static final Logger logger = LoggerFactory.getLogger(RequestDaoImpl.class);
#Inject
protected Session session;
#Resource(name = "sessionFactory")
protected SessionFactory sessionFactory;
/**
* #param sessionFactory the sessionFactory to set
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#SuppressWarnings("unchecked")
public <T, PK extends Serializable> T find(Class<T> type, PK id) {
return (T) session.get(type, id);
}
//other methods
}
Request DAO
public interface RequestDao extends AppDao {
}
Request DAO Implementation
#Repository("requestDao")
public class RequestDaoImpl extends AppDaoImpl implements RequestDao {
}
Generic service
public interface AppService {
/**
* #param <T>
* #param <PK>
* #param type
* #param id
* #return the object
*/
<T, PK extends Serializable> T find(Class<T> type, PK id);
//Other methods
}
Generic service implementation
#Service("appService")
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public class AppServiceImpl implements AppService {
#Autowired
private AppDao dao = null;
/**
* #return the dao
*/
public AppDao getDao() {
return dao;
}
/**
* #param dao
* the dao to set
*/
public void setDao(AppDao dao) {
this.dao = dao;
}
#Override
public <T, PK extends Serializable> T find(Class<T> type, PK id) {
return dao.find(type, id);//dao is null here
}
//other methods
}
Request Service
public interface RequestService extends AppService {
}
Request Service Implementation
#Service("requestService")
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public class RequestServiceImpl extends AppServiceImpl implements RequestService {
#Autowired
private RequestDao dao;
#Override
public Request find(Request request) {
dao.find(request);
}
//other methods
}
Usage in Tapestry pages
public class ManageRequest{
//dao needed for persistence operations
#InjectService("requestService")
protected requestService service;
}
While debugging the application we figured out that the service has been properly injected into the page but the dao has not been injected into the service. Can anybody tell me what is going wrong here?
This looks like Spring configuration issue, could it be that you need to specify sub package of your DAO services explicitly in <context:component-scan ... />, i.e.:
<context:component-scan base-package="org.prism.forecast, org.prism.forecast.dao" />
Some hints: #Autowired service is null, and multiple packages in context:component-scan.
#Component
#Transactional
public class TestClass extends AbstractClass
{
#Autowire
ClassARepo classARepo;
#Override
public void test() {
ClassA classA = classARepo.findOne(1);
List<ClassB> list = classA.getClassBs();
list.size();
}
}
ClassB is mapped as onetomany and lazily loaded.
In the above code
classARepo.findOne(1);
Executes correctly. but
List<ClassB> list = classA.getClassBs();
list.size();
Fails with LazyInitializationException.
public interface ClassARepo extends CrudRepository<ClassA, Integer> {
}
Instance for TestA is created like the one below
#PersistJobDataAfterExecution
#DisallowConcurrentExecution
#Transactional
#Component
public class TestClassJOB extends AbstractJob
{
#Autowired
TestClass indexer;
}
Context:
<!-- JPA mapping configuration -->
<bean id="persistenceXmlLocation" class="java.lang.String">
<constructor-arg value="classpath:/persistence.xml"></constructor-arg>
</bean>
<!-- entity manager -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource" p:persistenceUnitName="jpaData"
p:persistenceXmlLocation-ref="persistenceXmlLocation">
<property name="packagesToScan" value="com..persist.entity" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<!-- transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory" lazy-init="true" p:dataSource-ref="dataSource" />
<!-- JPA repositories -->
<jpa:repositories base-package="com..persist.repo"
entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager" />
I tried many resources and could not solve the issue. The following error message is displayed "could not initialize proxy - no Session".
What could be the cause of the issue?
When the session is available while classARepo.findOne(1) is called, why is not available during lazy fetch(list.size())?
The issue was the instance for TestClassJOB was created by Quartz. So the transnational proxy was not applied to the class which was the reason for the issue.
I fixed the issue by declaring a transaction template
#Autowired
TransactionTemplate transactionTemplate;
and then wrapping the code within
transactionTemplate.execute(new TransactionCallbackWithoutResult()
{
#Override
protected void doInTransactionWithoutResult(TransactionStatus status)
{
<code here>
}
}
Our current development based on Discriminator model in Multi-tenancy. Following is the technical stack we are currently engage with,
Spring 3.1.1.RELEASE
Hibernate 4.1.6.Final
We are maintain tenant id by keep one column separately in each table. Tenant id filter when session is created.
Example model class.
#Entity
#FilterDef(name = "tenantFilter", parameters = #ParamDef(name = "tenantIdParam", type = "string"))
#Filters(#Filter(name = "tenantFilter", condition = "tenant_id = :tenantIdParam"))
#Table(name = "assessment")
public class Assessment implements java.io.Serializable, Comparable<Assessment> {
private static final long serialVersionUID = -2231966582754667029L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
#Column(name = "tenant_id", nullable = false, updatable = false)
private String tenantId;
// rest of the code...
}
This is the configuration of session factory
<!-- create database connection pool -->
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="jdbc:mysql://${jdbc.host}:3306/${jdbc.database}?createDatabaseIfNotExist=true&autoReconnect=true&useUnicode=true&connectionCollation=utf8_general_ci&characterEncoding=UTF-8" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="idleConnectionTestPeriodInMinutes" value="60"/>
<property name="idleMaxAgeInMinutes" value="240"/>
<property name="maxConnectionsPerPartition" value="30"/>
<property name="minConnectionsPerPartition" value="10"/>
<property name="partitionCount" value="3"/>
<property name="acquireIncrement" value="5"/>
<property name="statementsCacheSize" value="100"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="lk.gov.elg.orm.model"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.hbm2ddl.auto=update
</value>
</property>
</bean>
<bean id="tenantBasedSessionFactory" class="lk.gov.elg.orm.dao.impl.TenantBasedSessionFactoryImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Tenant base session factory
public class TenantBasedSessionFactoryImpl implements TenantBasedSessionFactory {
private SessionFactory sessionFactory;
#Override
public Session getTenantBasedSession(Object tenantId) {
Session session = sessionFactory.openSession();
session.enableFilter("tenantFilter").setParameter("tenantIdParam", tenantId);
return session;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session getAllTenantBasedSession() {
Session session = sessionFactory.openSession();
return session;
}
}
sample Service class
#Service("assessmentService")
public class AssessmentServiceImpl implements AssessmentService {
#Autowired
private AssessmentDao assessmentDao;
public Long saveAssessment(Assessment assessment, Object tenantId) {
return assessmentDao.saveAssessment(assessment, tenantId);
}
}
Sample DAO class
#Repository("assessmentDao")
public class AssessmentDaoImpl implements AssessmentDao {
#Autowired
private TenantBasedSessionFactory tenantBasedSessionFactory;
public Long saveAssessment(Assessment assessment, Object tenantId) {
Session session = tenantBasedSessionFactory.getTenantBasedSession(tenantId);
try {
session.beginTransaction();
session.save(assessment);
session.getTransaction().commit();
return assessment.getId();
} catch (HibernateException e) {
logger.error("Error in persist assessment:", e);
session.getTransaction().rollback();
return null;
} finally {
session.close();
}
}
}
I would like to know is there a way to get the spring transaction support with this Discriminator model for database transactions ?
And the other thing is I would like to know is there any advantage of give transaction handling to spring rather than handling it by our side?
Thanks in advance.
i had similar problem and i have resolved it using aspect instead of customizing sessionfactory, so i can leverage annotation driven transaction support
Below code is for aspect which works on annotation #Tennant
#Aspect
public class TennantAspect {
#Autowired
private SessionFactory sessionFactory;
#Around("#annotation(Tennant)")
public Object enableClientFilter(ProceedingJoinPoint pjp) throws Throwable {
Object obj;
boolean isDAO=(pjp.getTarget() instanceof BaseDAO<?,?>);
try {
if(isDAO){
Authentication auth=SecurityContextHolder.getContext().getAuthentication();
if(auth!=null){
User user=(User) auth.getPrincipal();
this.sessionFactory.getCurrentSession().enableFilter("clientFilter").setParameter("clientId", user.getClientId());
}
}
obj=pjp.proceed();
}finally {
if(isDAO)
this.sessionFactory.getCurrentSession().disableFilter("clientFilter");
}
return obj;
}
}
Hope this solves your problem.
Alternatively you can also look at tenancy support by hiberante & spring
http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html/ch16.html
https://github.com/mariofts/spring-multitenancy
I've seen several similar questions, but none of the suggested solutions helped me.
Summary: when I create and inject the beans on the .xml, it works; but when I use #Autowire or #Resource, it doesn't.
Environment: Spring3, Hibernate4, Tomcat7.
Details: the following setup DOES work:
web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security-context.xml
/WEB-INF/spring/users-context.xml
</param-value>
</context-param>
root-context.xml:
<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/venus" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.airbus.genesis.marte.dal" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
users-context.xml:
<bean id="usersDAO" class="com.airbus.genesis.marte.dal.users.UsersDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
BL object:
#Service("usersManager")
#Transactional(readOnly = true)
public class UsersManager implements IUsersManager {
#Autowired
#Qualifier("usersDAO")
private IUsersDAO usersDAO;
#Override
public List<User> getUsers() {
return usersDAO.getUsers();
}
}
DAO object (notice that #Repository and #Resource are commented):
//#Repository("usersDAO")
#Transactional(readOnly = true)
public class UsersDAO implements IUsersDAO {
// #Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
#Override
public List<User> getUsers() {
#SuppressWarnings("unchecked")
List<User> res = (List<User>) getSessionFactory().getCurrentSession()
.createQuery("from User").list();
return res;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
But the following one DOES NOT work:
users-context.xml:
<!--
<bean id="usersDAO" class="com.airbus.genesis.marte.dal.users.UsersDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
-->
DAO object (notice that #Repository and #Resource are uncommented now):
#Repository("usersDAO")
#Transactional(readOnly = true)
public class UsersDAO implements IUsersDAO {
#Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
#Override
public List<User> getUsers() {
#SuppressWarnings("unchecked")
List<User> res = (List<User>) getSessionFactory().getCurrentSession()
.createQuery("from User").list();
return res;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
org.hibernate.HibernateException: No Session found for current thread is raised:
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:941)
com.airbus.genesis.marte.dal.users.UsersDAO.getUsers(UsersDAO.java:23)
com.airbus.genesis.marte.bl.users.UsersManager.getUsers(UsersManager.java:22)
[...]
The same happens if I use #Autowire instead of #Resource.
I guess it is some kind of misunderstanding on my side, but cannot find where. Any idea?
The problem is likely that #Repository and #Service annotations are being picked up in the dispatcher-servlet.xml configuration (do you use context:component-scan?), so these beans are created in the dispatcher servlet context instead of the root web app context.
A good practice is to put your service layer objects to the dedicated packages and use the specific package name as <context:component-scan/> base-package qualifier (like 'com.myproject.services'). You can also use filter expressions to include and exclude elements see examples here : #Service are constructed twice
and 4.10.3 section of the Spring documentation
See also Difference between applicationContext.xml and spring-servlet.xml in Spring Framework
Tried to configure Spring for tests with hibernate and transactions. Getting bean from app context which is marked with #Transactional transaction isn't intercepted. What I could miss in configuration?
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<import resource="spring-dao.xml"/>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="userService" class="com.test.service.UserServiceimpl">
<property name="userDao" ref="userDao"/>
</bean>
public interface UserService {
public abstract User loadUserById(long userId);
#Transactional
public abstract void doSomething();
}
public class UserServiceimpl implements UserService {
#Override
public void doSomething() {
User user = loadUserById(1);
user.fillUpMoney(999);
userDao.update(user);
throw new RuntimeException("Shpould be rollback");
}
Don't annotate the abstract method as transactional, annotate the concrete implementation.
Do not user BeanFactory ;)
http://forum.springsource.org/showthread.php?122292-Sprinng-doesnt-intercept-transaction