How I can configure the timeout for persiste() query of EntityManager ? I would like that the insert request never takes more time than 1 second!
Here is the code of DAO service :
#Service
#Transactional
public class DAOServiceImpl implements DAOService {
#PersistenceContext
private EntityManager entityManager;
public void save(DAOBean bean) {
entityManager.persist(bean);
}
}
Spring config file :
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/datasource" />
<property name="lookupOnStartup" value="true" />
<property name="resourceRef" value="true" />
<property name="cache" value="false" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
<property name="showSql" value="true"/>
</bean>
</property>
</bean>
<!-- Transactiom Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<task:annotation-driven />
<context:component-scan base-package="xx.xxx.xxx" />
</beans>
i am using sqljdbc-4.0.jar driver
Thanks.
Related
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>
I remix Spring Data and Hibernate in my Application to access MS-SQL Data.
In My All Service class,I set #Transactional(readOnly=true) in front of the class name.Recently,I observe some DB Table Locks occurrence.
Otherwise,I set#Transactional(readOnly=true,isolation = Isolation.READ_UNCOMMITTED) to avoid DB Table lock,but it throws
org.springframework.transaction.InvalidIsolationLevelException: Standard JPA does not support custom isolation levels - use a special JpaDialect for your JPA implementation.
How can I modify the XML to use isolation = Isolation.READ_UNCOMMITTED for dirty read?
<!-- JPA Configurations -->
<!-- <jee:jndi-lookup id="myContactDataSource" jndi-name="jdbc/GNWEB" lookup-on-startup="false"
proxy-interface="javax.sql.DataSource"/> -->
<!-- use annotation in Service: #Transactional -->
<bean id="transactionManager2" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<qualifier value="transactionManager2"/>
</bean>
<bean id="oracleConnection" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/OracleDB</value>
</property>
</bean>
<bean id="oracleTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="oracleConnection" />
<qualifier value="oracleConnectionTransactionManager"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="mssqlDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="url">
<value>${connection.url}</value>
</property>
<property name="username">
<value>${connection.username}</value>
</property>
<property name="password">
<value>${connection.1qaz#WSX}</value>
</property>
</bean>
<bean id="auditInterceptor" class="com.bot.gnweb.unit.AuditIntercepter"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" destroy-method="destroy">
<property name="dataSource" ref="mssqlDataSource" />
<property name="entityInterceptor" ref="auditInterceptor"/>
<property name="packagesToScan">
<value>com.bot.gnweb.model</value>
</property>
<property name="mappingResources">
<list>
<value>gnwebSql.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.dialect">com.bot.gnweb.model.MssqlCustomDialect</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="net.sf.ehcache.configurationResourceName">ehcache.xml</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="auditInterceptor">
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
<property name="persistenceUnitName" value="gnWebPU" />
<property name="dataSource" ref="mssqlDataSource" />
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
</bean>
<!-- Spring Data -->
<jpa:repositories base-package="com.bot.gnweb.repository"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager" />
<bean id="auditorBean" class="com.bot.gnweb.model.AuditingAware" />
<jpa:auditing auditor-aware-ref="auditorBean" />
I'm new in spring and trying to switch between 2 different DBs. I've made these changes in spring configuration xml file:
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:config/db-config.properties" />
</bean>
<!-- MS Sql DB -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<!-- end -->
<!-- MySql DB -->
<bean id="dataSourceMySql"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver1}" />
<property name="url" value="${db.url1}" />
<property name="username" value="${db.username1}" />
<property name="password" value="${db.password1}" />
</bean>
<!-- end -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.epam.model" />
<property name="dataSource" ref="dataSource" />
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto"></prop>
<prop key="hibernate.dialect"> org.hibernate.dialect.SQLServerDialect</prop>
</props>
</property>
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="entityManagerFactoryMySql"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.epam.model" />
<property name="dataSource" ref="dataSourceMySql" />
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto"></prop>
<prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManagerMySql" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryMySql" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<tx:annotation-driven transaction-manager="transactionManagerMySql" />
<jpa:repositories base-package="com.epam.repository" />
</beans>
what I need to add in repository or service to specify which db I want to work.
You can load the second data source using #Resource annotation
Thanks for responce. I'm just added 2nd db specific key/values in properties file and depending on the db type, just uncommented appropriate ones.
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!
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.