I am trying to implement a Session-Per-Conversation pattern in a JSF2-Spring-Hibernate Web App so I need my AnnotationSessionFactoryBean to build a Hibernate SessionFactory with a custom CurrentSessionContext class.
I have been receiving this error log:
org.springframework.dao.DataAccessResourceFailureException: Could not obtain Hibernate-managed Session for Spring-managed transaction; nested exception is org.hibernate.HibernateException: No CurrentSessionContext configured!
Here is my xml config for the whole data context used.
<?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:jdbc="http://www.springframework.org/schema/jdbc" xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-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/util http://www.springframework.org/schema/util/spring-util-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">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${datasource.driverClassName}" />
<property name="url" value="${datasource.url}" />
<property name="username" value="${datasource.username}" />
<property name="password" value="${datasource.password}" />
<property name="initialSize" value="${datasource.poolInitialSize}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${org.hibernate.dialect.dialectmysqlInno}</prop>
<prop key="hibernate.hbm2ddl.auto">${org.hibernate.ddl.mode}</prop>
<prop key="hibernate.search.default.directory_provider">${org.hibernate.search.directoryprovidr}</prop>
<prop key="hibernate.current_session_context_class">
mx.gob.jgtjo.apps.schedule.web.conversation.ConversationalCurrentSessionContext
</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="dataSource" ref="dataSource" />
<property name="hibernateManagedSession" value="true" />
</bean>
<tx:annotation-driven order="0" transaction-manager="transactionManager" />
<context:component-scan base-package="mx.gob.jgtjo.apps.schedule.dao.hibernate" />
</beans>
Also, here is my hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="jgtjoSessionFactory">
<!--Entity -->
<mapping class="mx.gob.jgtjo.apps.schedule.model.AudienciaOral" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.CausaPenal" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.DefensorPenal" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.Delito" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.EventoAudiencia" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.Juez" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.MinisterioPublico" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.ParteMaterial" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.Sala" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.TipoAudiencia" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.User" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.Rol" />
<mapping class="mx.gob.jgtjo.apps.schedule.model.DelitoConfigurado" />
</session-factory>
</hibernate-configuration>
As you can see, nothing tricky with hibernate xml.
Why I keep getting this exception?
java.lang.NoSuchMethodException: mx.gob.jgtjo.apps.schedule.web.conversation.ConversationalCurrentSessionContext.<init>(org.hibernate.engine.SessionFactoryImplementor)
It seems that hibernate looks for a constructor in my class that has a SessionFactory as argument.
This is the code from Hibernate which attempts to build the current session context using whatever value you passed in using the hibernate.current_session_context_class property:
private CurrentSessionContext buildCurrentSessionContext() {
String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
// for backward-compatability
if ( impl == null && transactionManager != null ) {
impl = "jta";
}
if ( impl == null ) {
return null;
}
else if ( "jta".equals( impl ) ) {
if ( settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions() ) {
log.warn( "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
}
return new JTASessionContext( this );
}
else if ( "thread".equals( impl ) ) {
return new ThreadLocalSessionContext( this );
}
else if ( "managed".equals( impl ) ) {
return new ManagedSessionContext( this );
}
else {
try {
Class implClass = ReflectHelper.classForName( impl );
return ( CurrentSessionContext ) implClass
.getConstructor( new Class[] { SessionFactoryImplementor.class } )
.newInstance( new Object[] { this } );
}
catch( Throwable t ) {
log.error( "Unable to construct current session context [" + impl + "]", t );
return null;
}
}
}
As you can see acceptable values are jta, thread, managed.
Since you're using Spring's transaction management functionality you shouldn't set this property at all. Spring will take care of this for you.
You just need to annotate your transactional methods with #Transactional and a session will be opened and bound to the current thread for you.
Ok, as the anwer above showed me the code and the logging I showed in my question edit the implementation of the CurrentSessionContext interface must have a public constructor with a sessionFactory as argument.
Hibernate docs never say anything like that.
and here is my class:
package mx.gob.jgtjo.apps.schedule.web.conversation;
import javax.servlet.http.HttpServletRequest;
import mx.gob.jgtjo.apps.schedule.web.utils.JsfUtils;
import org.hibernate.HibernateException;
import org.hibernate.classic.Session;
import org.hibernate.context.CurrentSessionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConversationalCurrentSessionContext implements CurrentSessionContext {
private static final long serialVersionUID = 803157986557235023L;
protected static final Logger log = LoggerFactory
.getLogger(ConversationalCurrentSessionContext.class);
public ConversationalCurrentSessionContext() {
}
#Override
public Session currentSession() throws HibernateException {
HttpServletRequest request = null;
try {
request = JsfUtils.getCurrentHttpRequest();
} catch (Exception e) {
log.debug("No current http request in faces context, returning default conversation.");
}
if (request == null) {
return (Session) ConversationManager.getDefaultConversationSession();
} else {
return (Session) ConversationManager.getSessionForRequest(request);
}
}
}
As you can see, I lack that constructor.
Related
I wrote this code in the Service part of my java webapp project:
#Service
#Transactional
public class PersonService extends BaseService {
#PersistenceContext
private EntityManager entityManager;
public void insert(Person person) {
entityManager.persist(person);
}
public boolean checkUserName(String userName) {
try {
System.out.println("Entity null ni");
Person person = (Person) entityManager.createQuery("select entity from person entity where entity.USER_NAME=:userName")
.setParameter("userName", userName)
.getSingleResult();
if (person == null)
return true;
else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
When I tried to insert a new record without using the checkUserName method, the record would be inserted correctly and entityManager was not null in this condition but when I wanted to check repetitive userName I got NullPointerException.I checked every Object in my code that could be null finally I understand entityManager is null.why entityManager is null in Spring Transaction.this is spring.xml
<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.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<!--SpringMVC-->
<context:component-scan base-package="Laitec.Doctor"/>
<mvc:annotation-driven/>
<mvc:resources mapping="/resources/**" location="/resources/"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
</bean>
<!-- SpringTransaction-->
<bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="Laitec.Doctor.model.entity"/><!--ToPackageAddress-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<!--<prop key="hibernate.hbm2ddl.auto">create-drop</prop>-->
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#localhost:1521:XE"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryBean"/>
</bean>
<tx:annotation-driven/>
</beans>
Maybe are you instantiating PersonService calling new PersonService() ? In this case Spring is not performing any operation and thus field 'entityManager' is null. You must get a bean from your Application Context
applicationContext.getBean(PersonService.class);
Or invoking it from a test or a controller
#RestController
#GetMapping("people")
public class PersonController() {
#Autowired
private PersonService personService;
#PostMapping
public void home(#RequestBody Person person) {
personService.insert(person);
}
}
I have written the below code to implment the transaction management of spring using #transactional annotation. I still feel some changes are required
in my DAO layer. May I know what changes are required . Thanks in advance
#Controller
public class RestController {
#Autowired
DataServices dataServices;
#RequestMapping(value = "/v1/dist_list/{emailId}/members", method = RequestMethod.GET)
public #ResponseBody String getDistributionListMember(#PathVariable String emailId) throws Exception, SpringException {
String retStatus = null;
retStatus = dataServices.getDistributionListMember(emailId, callerId);
]
}
}
DataServices.java
package com.uniteid.services;
import com.uniteid.model.AIWSuser;
public interface DataServices {
public String getDistributionListMember(final String emailId, final String callerID) throws Exception;
}
Below is my service layer where I added the trasactional attribute
package com.uniteid.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.uniteid.dao.DataDao;
import com.uniteid.model.AIWSuser;
#Service("dataService")
public class DataServicesImpl implements DataServices {
#Autowired
DataDao dataDao;
#Transactional
public String getDistributionListMember(String emailId, String callerID)
throws Exception {
return dataDao.getDistributionListMember(emailId, callerID);
}
}
Below is my spring-config 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:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
xmlns:tx="http://www.springframework.org/schema/tx">
<context:component-scan base-package="com.uniteid.controller" />
<mvc:annotation-driven
content-negotiation-manager="contentNegociationManager" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:uniteidrest.properties" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url">
<value>${eidms.url}</value>
</property>
<property name="username">
<value>${eidms.username}</value>
</property>
<property name="password">
<value>${eidms.password}</value>
</property>
</bean>
<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"
/> <property name="url" value="jdbc:oracle:thin:#nyvm0467.ptc.un.org:1521:EIDMSUAT"
/> <property name="username" value="DBO_EIDMSUAT" /> <property name="password"
value="NewPassDBO_EIDMSUAT" /> </bean> -->
<bean id="contentNegociationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="defaultContentType" value="application/json" />
<property name="ignoreAcceptHeader" value="true" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.uniteid.model.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.connection.pool_size">10</prop>
</props>
</property>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="dataDao" class="com.uniteid.dao.DataDaoImpl"></bean>
<bean id="dataServices" class="com.uniteid.services.DataServicesImpl"></bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
It still feel I have not implemented the Transactional management properly in the below code. May I know what part of the code can be removed for me to implement it
package com.uniteid.dao;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.jdbc.Work;
import org.springframework.beans.factory.annotation.Autowired;
import com.uniteid.controller.RestController;
import com.uniteid.model.AIWSuser;
import com.uniteid.model.User;
public class DataDaoImpl implements DataDao
{
#Autowired
\
SessionFactory sessionFactory;
Session session = null;
Transaction tx = null;
static final Logger logger = Logger.getLogger(DataDaoImpl.class);
public String getDistributionListMember(final String emailId, final String callerID) throws Exception {
session = sessionFactory.openSession();
tx = session.beginTransaction();
final String[] returnVal2 = { "" };
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
CallableStatement stmt = null;
String returnVal = "";
stmt = connection.prepareCall("{?=call WS_Distributionlistmember(?,?)}");
stmt.registerOutParameter(1, Types.VARCHAR);
stmt.setString(2, emailId);
stmt.setString(3, callerID);
stmt.execute();
returnVal = stmt.getString(1);
logger.info("RETURN VALUE in getDistributionListMember method :::::: " + returnVal);
returnVal2[0] = returnVal;
logger.info("Return Value " + returnVal);
stmt.close();
}
});
tx.commit();
session.close();
return returnVal2[0];
}
}
Your code:
public String getDistributionListMember(final String emailId, final String callerID) throws Exception {
session = sessionFactory.openSession();//This is bad
tx = session.beginTransaction();//This is bad
tx.commit();//This is bad
session.close();//This is bad
Correct should be:
public String getDistributionListMember(final String emailId, final String callerID) throws Exception {
session = sessionFactory.getCurrentSession();//good way
It is because you told spring to autowired sessionFactory and from now on spring is managing your hibernate session not you. So getCurrentSession() is correct way.
#M. Deinum Thanks to point it out.
Remove bean declaration for bean id transactionManager and set txManager instead of transactionManager in transaction-manager value. As you are using hibernate with spring so HibernateTransactionManager should be used instead of DatabaseTransactionManager to define transaction boundary. DatabaseTransactionManager is used when you directly interact with data source without using any ORM or JPA framework.
In your service class define transaction boundary for method as below annotation
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
I am trying to define the transaction in my spring mvc project but having problem:
// xml 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:context
="http://www.springframework.org/schema/context"
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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Enable Annotation based Declarative Transaction Management -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Creating TransactionManager Bean, since JDBC we are creating of type DataSourceTransactionManager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Initialization for data source -->
<bean id="dataSource" class= "org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost/bhaiyag_devgrocery"></property>
<property name="username" value="newuser"></property>
<property name="password" value="kim"></property>
</bean>
<bean id="CategoriesDaoImpl" class="org.kmsg.dao.daoImpl.CategoriesDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="CityDaoImpl" class="org.kmsg.dao.daoImpl.CityDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="CustomerDaoImpl" class="org.kmsg.dao.daoImpl.CustomerDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
// This is class where i want to apply the transaction
public class CustomerOrderAdapter
{
public void displayCustomerOrder(String mobileNo)
{ }
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = true)
public Map<String, Object> createCustomerOrderData(SalesCommandObject salesCommandObject,long OrderForDelete) throws Exception
{
Map <String, Object> data = new HashMap<String, Object>();
try
{
salesDaoImpl.deleteSalesitems(OrderNo);
salesDaoImpl.deleteSales(OrderNo);
salesDaoImpl.insertSalesItems(updatedOn,OrderNo,CustmobileNo);
salesDaoImpl.insertSales(totalSale, SlotNo, OrderNo);
}
catch(IndexOutOfBoundsException ex)
{
System.out.println("No Record to Save");
data.put("status", "No Record to Save");
}
catch(Exception e)
{
System.out.println(e.toString());
data.put("status", e);
}
data.put("status", "Purchase Successfull");
return data;
}
}
// Help me and suggest , How to implement transaction;
The setup I have an old project that is stuck to jdk 1.5, thus spring and hibernate versions are also the maximum possible to support this version of java. Hibernate is 3.3.2.GA and spring is 3.1.1.RELEASE. Setup is the following:
<persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
<mapping-file>persistence-query.xml</mapping-file>
...
<properties>
<property name="hibernate.max_fetch_depth" value="3" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.ejb.interceptor" value="com.myproj.common.dao.AuditInterceptor"/>
</properties>
</persistence-unit>
application context:
<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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:component-scan base-package="..."/>
<tx:annotation-driven transaction-manager="transactionManager" />
<aop:aspectj-autoproxy/>
<bean id="applicationContextProvder" class="com.myproj.common.utils.ApplicationContextProvider"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="persistenceUnitName" value="myUnit" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<!-- Local transaction management -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
and my interceptor:
#Component
public class AuditInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 98658932451L;
#Autowired
private JdbcTemplate jdbcTemplate;
public void afterTransactionBegin(Transaction tx) {
if (user != null) {
jdbcTemplate.execute("call ah_audit_pkg.SetAudit('test')");
super.afterTransactionBegin(tx);
}
}
}
I run a junit to test that interceptor is getting called and it is not. In debug mode, I am able to see this:
Any help is appreciated! Why my intercetprot is not getting called.
Edit:
I also tried the interceptor to override the afterTransactionBegin but it didn't help.
I ended up with the following solution:
I have my entityt that extends from a superclass mapped entity:
#Entity
#Table(name = "my_table")
public class MyTable extends AuditInfo
The AuditInfo entity has the following mapping:
#MappedSuperclass
public abstract class AuditInfo implements Serializable {
...
#PrePersist
void onCreate() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is stored
}
#PreUpdate
void onPersist() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is updated
}
#PreRemove
void onRemove() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is removed
}
}
And the Aspect class:
#Aspect
#Component
public class MyAspect {
#Before("execution(* com.mypackage.entities.AuditInfo.on*(..))")
public void setAuditHistory(JoinPoint jp){
final AuditInfo info = ((AuditInfo)jp.getThis());
JdbcTemplate jdbcTemplate = ApplicationContextProvider.getApplicationContext().getBean(JdbcTemplate.class);
jdbcTemplate.execute(new CallableStatementCreator() {
public CallableStatement createCallableStatement(Connection conn) throws SQLException {
CallableStatement stmt = conn.prepareCall("begin ah_audit_pkg.SetAudit(?,?); end;");
stmt.setString(1, info.getAuditUser());
if(info.getAuditLocation() != null && info.getAuditLocation().trim().length() !=0) {
stmt.setString(2, info.getAuditLocation());
} else {
stmt.setString(2, info.getAuditUser());
}
return stmt;
}
}, new CallableStatementCallback<Object>() {
public Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
return cs.executeUpdate();
}
});
}
}
It is to be noted that the Spring beans are extracted from the context and not autowired - this is because AOP is a singleton class in spring implementation, and none of the autowired beans will be ever instantiated even if they are available in the context. So I had to manually retrieve them for later usage.
I am new to spring mvc and hibernate.
How to close connection in spring mvc applction. I am very frustrated from this issue.
This is my code:
Dispatcher servlet:
<?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:context="http://www.springframework.org/schema/context"
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">
<context:component-scan base-package="com.kqics" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
<bean id="userService" class="com.kqics.dao.kqtraveldao">
</bean>
<bean id="viewResolver1" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="order" value="1"/>
<property name="basename" value="views"/>
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="10000000" />
</bean>
<import resource="db-config.xml" />
</beans>
dbconfig.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/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">
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"><value>/WEB-INF/jdbc.properties</value></property>
</bean>
<bean id="dataSourceBean" lazy-init="true" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}"/>
<property name="acquireIncrement" value="${jdbc.acquireIncrement}" />
<property name="minPoolSize" value="${jdbc.minPoolSize}" />
<property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
<property name="maxIdleTime" value="${jdbc.maxIdleTime}" />
<property name="numHelperThreads" value="${jdbc.numHelperThreads}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
p:dataSource-ref="dataSourceBean"
p:packagesToScan="com.kqics" >
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">create</prop> -->
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.connection.release_mode">after_transaction</prop>
<prop key="hibernate.connection.shutdown">true</prop>
</props>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ><ref bean="sessionFactory"/></property>
</bean>
</beans>
my service class:
#Service
public class kqtravellogservice implements ikqtravellogservice {
#Autowired
ikqtraveldao iDao;
#Transactional
public void serviceaddnewvehicle(kqvehicle obj) {
// TODO Auto-generated method stub
iDao.addnewvehicle(obj);
}
#Transactional
public List<kqvehicle> servicefetchallvehicle() {
return iDao.fetchallvehicle();
}
#Transactional
public void serviceaddnewvehicletariff(kqvehicletariff obj,String tariff) {
iDao.addnewvehicletariff(obj,tariff);
}
dao impl
public class kqtraveldao implements ikqtraveldao {
private HibernateTemplate hibernateTemplate;
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
try {
hibernateTemplate = new HibernateTemplate(sessionFactory);
} catch (Exception w) {
}
}
#Override
public void addnewvehicle(kqvehicle obj) {
hibernateTemplate.save(obj);
}
#SuppressWarnings("unchecked")
#Override
public List<kqvehicle> fetchallvehicle() {
List<kqvehicle> li=null;
li=hibernateTemplate.find("from kqvehicle");
return li;
}
#Override
public void addnewvehicletariff(kqvehicletariff obj, String tariff) {
try
{
hibernateTemplate.getSessionFactory()
.openSession()
.createSQLQuery("insert into "+tariff+" values(?,?,?,?,?)")
.setParameter(0, obj.getTid())
.setParameter(1, obj.getVehicletype())
.setParameter(2, obj.getRupees())
.setParameter(3, obj.getDateupto())
.setParameter(4, obj.getDatetimedetermined())
.executeUpdate();
}
catch(Exception e)
{
}
finally
{
hibernateTemplate.getSessionFactory().close();
}
}
Some friends told me as i am not using singleton, connection closing.. so, i got the too many connection error... Please advice me how to resolve this problem...
What are the changes is needed for my code....
The problem is in your dao, your save method is destroying springs proper tx management. You should NEVER call openSession() when you are using Spring to manage your connections and sessions.
Instead use a HibernateCallback which will give you a spring managed session.
#Override
public void addnewvehicletariff(final kqvehicletariff obj, final String tariff) {
hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
session.createSQLQuery("insert into "+tariff+" values(?,?,?,?,?)")
.setParameter(0, obj.getTid())
.setParameter(1, obj.getVehicletype())
.setParameter(2, obj.getRupees())
.setParameter(3, obj.getDateupto())
.setParameter(4, obj.getDatetimedetermined())
.executeUpdate();
}
}
}
Another note is that you shouldn't be using HibernateTemplate anymore, you should write code against the plain hibernate API using the getCurrentSession() method on the SessionFactory. See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html#orm-hibernate-straight for more information.
public class kqtraveldao implements ikqtraveldao {
private SessionFactory sessionFactory;
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory=sessionFactory;
}
#Override
public void addnewvehicle(kqvehicle obj) {
sessionFactory.getCurrentSession().save(obj);
}
#SuppressWarnings("unchecked")
#Override
public List<kqvehicle> fetchallvehicle() {
return sessionFactory.getCurrentSession()
.createQuery("from kqvehicle")
.list();
}
#Override
public void addnewvehicletariff(kqvehicletariff obj, String tariff) {
sessionFactory.getCurrentSession()
.createSQLQuery("insert into "+tariff+" values(?,?,?,?,?)")
.setParameter(0, obj.getTid())
.setParameter(1, obj.getVehicletype())
.setParameter(2, obj.getRupees())
.setParameter(3, obj.getDateupto())
.setParameter(4, obj.getDatetimedetermined())
.executeUpdate();
}
}
just autowire the sessionfactory in the dao and remove the method set session factory.
#Autowired
private SessionFactory sessionfactory;
you can close the connection by calling sessionfactory.getCurrentSession().close() in your method.
the Session factory is the 'singleton' in your application.