My project initially develop using with out persistence unit and project is spring,Struts2 hibernate intergration one. Now I need to use jboss connection pool and persistence unit.
Can any one guild me to shortest way to convert project in that requirement.
current spring.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>properties/database.properties</value>
</property>
</bean>
<bean id="springdatasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<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="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="springdatasource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>model.AtOrganisation</value>
<value>model.AtDivision</value>
</list>
</property>
</bean>
<bean id="orgdao" class="dao.OrganisationDaoImp">
<property name="sessionfactory" ref="sessionFactory" />
</bean>
<bean id="divdao" class="dao.DevisionDaoImpl">
<property name="sessionfactory" ref="sessionFactory" />
</bean>
<bean id="empAction" class="action.OraganisationAction">
<property name="orgdao" ref="orgdao" />
</bean>
<bean id="empAction2" class="action.DevisionAction">
<property name="orgdao" ref="orgdao" />
</bean>
<bean id="divAction" class="action.DevisionAction">
<property name="divdao" ref="divdao" />
</bean>
sample DAO class
public class DevisionDaoImpl implements DevisionDao {
private SessionFactory sessionfactory;
public void setSessionfactory(SessionFactory sessionfactory) {
this.sessionfactory = sessionfactory;
}
#Override
public List showDiv() {
// TODO Auto-generated method stub
return null;
}
#Override
public void addDiv(AtDivision div) {
Session session = sessionfactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
session.saveOrUpdate(div);
tx.commit();
//System.out.println("after save : " + org.getAoId());
} catch (Exception e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
}
1: change your datasource config to use the jboss datasource. This can be done like this :
<jee:jndi-lookup id="springdatasource" jndi-name="your-de-jndi-name" />
2: Add a transaction manager to control the transactions using spring transaction manager:
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
3: Add annotation support for spring transactions. Add this to your config:
<tx:annotation-driven transaction-manager="transactionManager" />
4: Finally decorate your Dao classes with #Transactional
Related
I'm using hibernate integrated with Spring annotation and getting FileNotFoundException for my Entity class
This is my applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/db1"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="mysessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mappingResources">
<list>
<value>vendors.Vendor</value>
<value>accountBooks.DayBookData</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="template" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="mysessionFactory"></property>
</bean>
<bean id="vendor" class="vendors.VendorDao">
<property name="hibernateTemplate" ref="template"></property>
</bean>
<bean id="dayBook" class="accountBooks.DayBookDao">
<property name="hibernateTemplate" ref="template"></property>
</bean>
</beans>
My Dao class
public class DayBookDao {
private HibernateTemplate hibernateTemplate;
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
public void saveDayBookData(DayBookData dayBook){
hibernateTemplate.save(dayBook);
}
public void updateDayBookData(DayBookData dayBook){
hibernateTemplate.update(dayBook);
}
public void deleteDayBookData(DayBookData dayBook){
hibernateTemplate.delete(dayBook);
}
public List<DayBookData> getDayBookData(){
List<DayBookData> dayBook = hibernateTemplate.loadAll(DayBookData.class);
return dayBook;
}
}
My Main class
public static void main(String[] args) {
// TODO Auto-generated method stub
Resource r = new ClassPathResource("applicationContext.xml");
BeanFactory bean = new XmlBeanFactory(r);
DayBookDao dayBookDao = (DayBookDao) bean.getBean("dayBook");
DayBookData dayBook = new DayBookData();
dayBook.setAccountType("Bank Account");
dayBook.setTransType("Receipt");
dayBook.setOppAccount("Profit-Loss");
dayBook.setAmount(15000);
dayBook.setTransDate(new Date());
dayBookDao.saveDayBookData(dayBook);
}
I'm getting error
**Caused by: java.io.FileNotFoundException: class path resource [vendors.Vendor] cannot be opened because it does not exist
Property mappingResources are used for XML (hbm.xml) mapping.
Hibernae 4 and above
You just need to put all your persistent classes to the some.package.model package and use
<property name="packagesToScan" value="some.package.model" />
to add all classes from that package. Inner packages are processed as well.
Also you can add persistent classes separately using
<property name="annotatedClasses">
<list>
<value>vendors.Vendor</value>
<value>accountBooks.DayBookData</value>
</list>
</property>
Hibernate 3
Hibearnate 3 configuration using annotated persistent classes and Spring a bit more complex.
It is need to add persistent classes to the hibernate.cfg.xml and configure Spring by this way:
<bean id="mysessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
</bean>
Hibernate 3 uses a separate config class for configurations with annotations:
org.hibernate.cfg.AnnotationConfiguration
I was using sessionFactory by autowiring it in my DAOImpl files.
Things were working fine until I started facing an issue of "Too many database connections" in certain DAO methods. After searching for possible reasons and solutions, I realized that I might have misconfigured my applicationContext.xml and the way I am using EntityManager is incorrect.
Below is my applicationContext.xml file content:
<?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-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- Enables the Spring MVC #Controller programming model -->
<!-- enables cors (cross origin request) for all urls -->
<mvc:cors>
<mvc:mapping path="/**" />
</mvc:cors>
<!-- <mvc:annotation-driven /> -->
<mvc:annotation-driven>
<mvc:message-converters>
<!-- Use the HibernateAware mapper instead of the default -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.typjaipur.core.objectmapper.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<context:component-scan base-package="com.typjaipur" />
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="propertyPlaceholder" class="com.typjaipur.core.config.EnvironmentPropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
<value>classpath:core.properties</value>
<value>classpath:mailer.properties</value>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.typjaipur.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.default_batch_fetch_size">4</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">20</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
</props>
</property>
</bean>
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="hibernateTransactionManager" />
<mvc:interceptors>
<bean class="org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<mvc:interceptor>
<mvc:mapping path="/**" />
<!-- excluded urls -->
<mvc:exclude-mapping path="/" />
<bean class="com.typjaipur.interceptor.ApiAuthenticationInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
<!-- Enables swgger ui -->
<mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/" />
<mvc:resources mapping="/webjars/**"
location="classpath:/META-INF/resources/webjars/" />
<!-- Include a swagger configuration -->
<bean name="/applicationSwaggerConfig" class="com.typjaipur.config.SwaggerConfig" />
<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="100000"/> -->
</bean>
</beans>
Below is DAOImpl code example of how I am using EntityManager which is working too but I feel its not correct maybe.
#Repository
public class BusinessDetailsDAOImpl extends BaseDAOImpl<BusinessDetails, Long> implements BusinessDetailsDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public List<BusinessDetails> searchBusiness(BusinessSearchDTO businessSearchDTO, List<Long> businessIds) {
EntityManager entityManager = sessionFactory.getCurrentSession().getEntityManagerFactory().createEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<BusinessDetails> query = criteriaBuilder.createQuery(BusinessDetails.class);
Root<BusinessDetails> businessDetails = query.from(BusinessDetails.class);
List<Predicate> predicates = new ArrayList<Predicate>();
...//rest of code
It is tough for me to avoid sessionFactory at this point as I have used it all over my project. Is there anyway through which I can configure my xml file to allow me to use EntityManager as well as SessionFactory together?
I saw several examples of configuring EntityManager but none of them has added any line in xml file related to SessionFactory. So I am confused in this.
Use LocalContainerEntityManagerFactoryBean to create the EntityManager instead of using LocalSessionFactoryBean, so you do not have call sessionFactory.getCurrentSession().getEntityManagerFactory().createEntityManager() to get the entityManager :
In spring config file replace this current config with :
<!-- Create a datasource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
<!-- Create an Hibernate to Jpa adapter -->
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="false" />
<property name="database" value="MYSQL" />
</bean>
<!-- persistenceUnitManager is optional -->
<bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="defaultDataSource" ref="dataSource"/>
</bean>
<!-- create entityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
</bean>
<!-- and create transactionManager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
Use it like this :
#Repository
public class BusinessDetailsDAOImpl extends BaseDAOImpl<BusinessDetails, Long> implements BusinessDetailsDAO {
#PersistenceContext
protected EntityManager entityManager;
#Override
public List<BusinessDetails> searchBusiness(BusinessSearchDTO businessSearchDTO, List<Long> businessIds) {
// use directly entityManager instead of sessionFactory.getCurrentSession().getEntityManagerFactory().createEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
// ...
}
Edit : update your config as follow :
<property name="jpaProperties">
<props>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<!-- add this line -->
<prop key="hibernate.enable_lazy_load_no_trans">true</prop>
</props>
</property>
Good morning , I'm still new with hibernate jpa and spring this is my first projet I make and every time i try to execute it I got npe. This is my code
applicationContext.xml
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dao" class="com.talan.springmvc.dao.AdminDaoImpl">
</bean>
<bean id="metier" class="com.talan.springmvc.metier.AdminMetier">
<property name="dao" ref="dao" />
</bean>
<bean id="datasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="url" value="jdbc:oracle:thin:#localhost:1521/XE"></property>
<property name="username" value="system"></property>
<property name="password" value="Islem1992"></property>
</bean>
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>classpath*:META-INF/persistence.xml</value>
</list>
</property>
<property name="defaultDataSource" ref="datasource"></property>
</bean>
<bean id="entityManagerFactory
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager"></property>
<property name="dataSource" ref="datasource" />
<property name="persistenceUnitName" value="myapp"></property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">none</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
</props>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
</bean>
</property>
</bean>
<!-- <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myapp"></property> </bean> -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="myapp"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
</persistence-unit>
</persistence>
Test.java
package test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.talan.springmvc.entities.Agence;
import com.talan.springmvc.entities.User;
import com.talan.springmvc.metier.IAdminMetier;
public class Test {
public static void main(String[] args){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
IAdminMetier admin = (IAdminMetier) context.getBean("metier");
User u = new User(1,"islem", "yeddes", "salesAgent");
admin.addUser(u);
}
}
I forgot to post my DAO
package com.talan.springmvc.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.talan.springmvc.entities.User;
public class AdminDaoImpl implements IAdminDao {
#PersistenceContext
private EntityManager em;
#Override
public User addUser(User u) {
em.persist(u);
return u;
}
}
First of all, there is a problem with your DataSource, which is unable to handle a database pool for db connections.
org.springframework.jdbc.datasource.DriverManagerDataSource is creating a new Connection for each HttpRequest, which is suitable for test purposes only...
Use dbcp from Tomcat:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>8.0.32</version>
</dependency>
or from other providers as c3p0 or vibur which are able to handle that job greatly.
Second, you'll need to add #Service("serviceName") and some #Autowired annotations in order to provide your code dependencies with Spring IoC mecanism. Maybe adding some #ComponentScan("com.talan.springmvc.dao") inside your Service too.
In one of my project, I have a Service which is defined with that:
#Service("utilisateurService")
public class UtilisateurService implements UserDetailsService {
public static final Logger logger = LoggerFactory.getLogger(UtilisateurService.class);
private EntityManager entityManager;
#PersistenceContext
public void setEntityManager(EntityManager newEm){
this.entityManager = newEm;
}
#Override
#Transactional
public UserSpringSecurity loadUserByUsername(final String username) throws UsernameNotFoundException {
}
// etc.
}
And of course there is some beans to define my "utitisateurService". In XML:
<context:annotation-config />
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dsn1" class="org.vibur.dbcp.ViburDBCPDataSource"
init-method="start" destroy-method="terminate">
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="poolInitialSize" value="10" />
<property name="poolMaxSize" value="50" />
<property name="connectionIdleLimitInSeconds" value="30" />
<property name="testConnectionQuery" value="SELECT 1" />
<property name="logQueryExecutionLongerThanMs" value="500" />
<property name="logStackTraceForLongQueryExecution" value="true" />
<property name="statementCacheMaxSize" value="200" />
</bean>
<bean id="crmEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" autowire="byName">
<property name="persistenceUnitName" value="crmPersistenceUnit" />
<property name="dataSource" ref="dsn1" />
<property name="packagesToScan" value="crm.db.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="crmEmf"></property>
</bean>
<tx:annotation-driven proxy-target-class="true" mode="proxy" />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<!-- Logging -->
<bean id="loggerListener"
class="org.springframework.security.authentication.event.LoggerListener" />
<bean id="customAuthenticationProvider" class="crm.security.CustomAuthenticationProvider" />
<bean id="utilisateurService" class="crm.service.UtilisateurService"/>
Try that way and tell us if it works!
Hi i am try to develop spring and hibernate app with transactions , i am using spring 4.x and hibernate 4.x , here is my code snippet
applicationContext.xml
<tx:annotation-driven />
<context:annotation-config />
<context:component-scan base-package="com.xyx.service" />
<context:component-scan base-package="com.xyz.dao" />
<import resource="conf/spring/persistence.xml" />
servlet-context.xml
<context:component-scan base-package="com.xyx.webservice.components" />
<mvc:annotation-driven />
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
<!-- Configure to plugin JSON as request and response in method handler -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter"/>
</list>
</property>
</bean>
persistance.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/xyx" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="packagesToScan" value="com.xyz.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
</props>
</property>
</bean>
<bean id = "transactionManager" class = "org.springframework.orm.hibernate4.HibernateTransactionManager" p:sessionFactory-ref= "sessionFactory" >
</bean>
</beans>
and finnaly meservice look like this
#Transactional(propagation=Propagation.REQUIRED,rollbackFor=RuntimeException.class)
public Object loadCategories(UserContactsInputVO inputVo) {
User user= getUserObject(inputVo);
userDAO.saveOrUpdateForTrancasction(user);
System.out.println(user.getUserId());
//getAudioFilesBasedOnCategories();
try{
return getAudioFilesBasedOnCategories();
}catch (RuntimeException e) {
e.printStackTrace();
}
return new CategoryResponseVo();
}
and
#Transactional(propagation=Propagation.REQUIRED)
public CategoryResponseVo getAudioFilesBasedOnCategories()
{
try{
if(true)
throw new RuntimeException();
}finally{
}
return vo;
}
here runtime exception occurs but db records are not rolled backed.
The reason the transaction is not getting rolled back is beacause the RuntimeException is not getting propagated to the actual Spring proxy which manages the transaction rollback code. And the reason it is not being propagated is that you have caught it and have not rethrown.
try{
return getAudioFilesBasedOnCategories();
}catch (RuntimeException e) {
e.printStackTrace(); //**THIS IS WRONG**
}
Instead do this
try{
return getAudioFilesBasedOnCategories();
}catch (RuntimeException e) {
//log the error
throw e; // throw back
}
Also you probably do not need to give rollbackFor attribute as by default on RuntimeException, the transaction is rolled back.
The interface for service layer is :
EMS.java:
public interface EMS extends UserDetailsService {
public void saveUser(User user);
}
and its implementation:
EMSImpl.java:
#Service("emsImpl")
#Transactional(readOnly=true)
public class EMSImpl implements EMS {
private final Logger logger = LoggerFactory.getLogger(getClass());
#Autowired
#Qualifier("dao")
private EMSDao dao;
#Transactional(readOnly=false)
public void saveUser(User user) {
dao.saveUser();
}
}
The interface for dao:
EMSDao.java:
public interface EMSDao {
public void saveUser(User user);
}
And its implementation:
HibernateEMSDao.java
#Repository("EMSDao")
public class HibernateEMSDao extends HibernateDaoSupport implements EMSDao {
private final Logger logger = LoggerFactory.getLogger(getClass());
private SchemaHelper schemaHelper;
public void setSchemaHelper(SchemaHelper schemaHelper) {
this.schemaHelper = schemaHelper;
}
#Transactional(readOnly=false)
public synchronized void saveUser(final User user) {
Session session = getSessionFactory().getCurrentSession();
session.merge(user);
}
private void storeUser(User user) {
getHibernateTemplate().save(user);
}
public void createSchema() {
try {
getHibernateTemplate().find("from User user where user.id = 1");
} catch (Exception e) {
logger.warn("expected database schema does not exist, will create. Error is: " + e.getMessage());
schemaHelper.createSchema();
User admin = new User();
admin.setUsername("admin");
admin.setName("Admin");
admin.setEmail("admin");
admin.setPassword("21232f297a57a5a743894a0e4a801fc3");
admin.setRoles(new HashSet<Role>(Arrays.asList(new Role("admin", "ADMINISTRATOR"))));
logger.info("inserting default admin user into database");
storeUser(admin);
logger.info("schema creation complete");
return;
}
logger.info("database schema exists, normal startup");
}
}
The bean ems in appliactionContext.xml is created by TransactionProxyFactoryBean. Also I am using <tx:annotation-driven />
The complete applicationContext.xml 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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean class="info.ems.config.EMSConfigurer"/>
<bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>
<bean id="ems" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target">
<bean class="info.ems.EMSImpl" init-method="init">
<property name="dao" ref="dao"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
<property name="localeList" value="${ems.locales}"/>
<property name="releaseVersion" value="${ems.version}"/>
<property name="releaseTimestamp" value="${ems.timestamp}"/>
<property name="emsHome" value="${ems.home}"/>
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="store*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="bulkUpdate*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="dataSource" class="info.ems.datasource.DataSourceFactory">
<property name="driverClassName" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="validationQuery" value="${database.validationQuery}"/>
<property name="dataSourceJndiName" value="${database.datasource.jndiname}"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation">
<value>/WEB-INF/hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</prop>
</props>
</property>
</bean>
<bean id="dao" class="info.ems.hibernate.HibernateEMSDao" init-method="createSchema">
<property name="hibernateTemplate">
<bean class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</property>
<property name="schemaHelper">
<bean class="info.ems.hibernate.SchemaHelper">
<property name="driverClassName" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="hibernateDialect" value="${hibernate.dialect}"/>
<property name="dataSourceJndiName" value="${database.datasource.jndiname}"/>
</bean>
</property>
</bean>
</beans>
I want to know:
Is it the right configuration for handling database transaction by spring?
Is it needed to use TransactionProxyFactoryBean along with <tx:annotation-driven />?
Any information or web-link where I can get example will be very helpful.
Thanks and regards.
Edit: after getting suggestion from skaffman the modified appliactionContext.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean class="info.ems.config.EMSConfigurer"/>
<bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>
<bean id="ems" class="info.ems.EMSImpl" init-method="init">
<property name="dao" ref="dao"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
<property name="localeList" value="${ems.locales}"/>
<property name="releaseVersion" value="${ems.version}"/>
<property name="releaseTimestamp" value="${ems.timestamp}"/>
<property name="emsHome" value="${ems.home}"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="dataSource" class="info.ems.datasource.DataSourceFactory">
<property name="driverClassName" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="validationQuery" value="${database.validationQuery}"/>
<property name="dataSourceJndiName" value="${database.datasource.jndiname}"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation">
<value>/WEB-INF/hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</prop>
</props>
</property>
</bean>
<bean id="dao" class="info.ems.hibernate.HibernateEMSDao" init-method="createSchema">
<property name="hibernateTemplate">
<bean class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</property>
<property name="schemaHelper">
<bean class="info.ems.hibernate.SchemaHelper">
<property name="driverClassName" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="hibernateDialect" value="${hibernate.dialect}"/>
<property name="dataSourceJndiName" value="${database.datasource.jndiname}"/>
</bean>
</property>
</bean>
</beans>
Is it the right configuration for handling database transaction by spring?
It's perfectly valid, but it's confusing and duplicates work. This will probably generate two layers of transactional proxies, although I doubt that will behave any differently.
As you say, you probably don't want to use both TransactionProxyFactoryBean and <tx:annotation-driven /> at the same time.
Your TransactionProxyFactoryBean config is using externalised method name patterns to decide which methods get which transaction semantics. This is fine, although with current versions of Spring it's usually easier to use annotations instead of the transactionAttributes property on TransactionProxyFactoryBean.
Given your config, I suggest getting rid of the explicit TransactionProxyFactoryBean bean definition (<tx:annotation-driven /> will create its own one as required, behind the scenes). Replace that with the undecorated EMSImpl, and <tx:annotation-driven /> will generate the transaction proxy automatically.