Currently, I am working on one project in spring and hibernate.I struck here. It is taking more time to fetch records and show those records in JSP. I kept Timestamps everywhere to see where it is taking more time:
Time # HomeController[start] : 2014-07-09 18:58:52.621
**Time # userService[start] : 2014-07-09 18:58:52.622**
**Time # UserDao[start] : 2014-07-09 18:58:57.678**
Time before executing Query : 2014-07-09 18:58:57.678
Time After executing Query : 2014-07-09 18:58:59.272
Time # UserDao[end] : 2014-07-09 18:58:59.272
Time # userService[End] : 2014-07-09 18:59:00.068
Time # HomeController[end] : 2014-07-09 18:59:00.068
Time stamp in JSP :2014-07-09 18:59:00.129
From above analysis, it is taking almost 5 sec to go from Service layer to DAO layer and I am giving code of Service and DAO below:
UserService :
public class UserServiceImpl implements UserService {
#Override
public List<User> getUserpagination(int page) {
System.out.println("Time # userService[start] : "+new Timestamp(new Date().getTime())); ----------- (1)
List<User> u = userDao.getUserpagination(page);
System.out.println("Time # userService[End] : "+new Timestamp(new Date().getTime()));
return u;
}
}
UserDao :
public class UserDaoImpl implements UserDao {
#Override
#Transactional
public List<User> getUserpagination(int page) {
System.out.println("Time # UserDao[start] : "+new Timestamp(new Date().getTime())); ------- (2)
return userlist;
}
So, It is taking 5 sec to go from line (1) to line (2). Can anyone explain why and how to reduce that time?
I am getting database connection from properties file :
jdbc.properties :
database.driver=oracle.jdbc.driver.OracleDriver
database.url=jdbc:oracle:thin:#xxx.xxx.xxx.xx:1521:osm
database.user=osm
database.password=xxxxxx
hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=create/update
And below is the configuration in XML file :
<context:property-placeholder location="classpath:jdbc.properties" />
<tx:annotation-driven transaction-manager="hibernateTransactionManager" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.xxx</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Now, I used HikariCP and I am getting Timeout Error :
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/springhiber1] threw exception [Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.exception.GenericJDBCException: Cannot open connection] with root cause
java.sql.SQLException: Timeout of 30000ms encountered waiting for connection.
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:192)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:91)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
In your configuration you are using the DriverManagerDataSource whilst this is a proper datasource implementation it is only that. It is not a connection pool. What happens is that each connection is created on demand and as soon it needs to be closed it will be actually closed. This is a killer for performance.
If you want to have performance use a connection pool. There are plenty of implementations out there
Tomcat JDBC
Commons DBCP
C3P0
HikariCP
Simply replace your dataSource bean definition with a proper connection pool. For instance if you would want to replace it with HikariCP something like this would work.
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="shutdown">
<property name="dataSourceClassName" value="oracle.jdbc.pool.OracleDataSource" />
<property name="connectionTestQuery" value="SELECT 1 FROM DUAL" />
<property name="dataSource.user" value="${database.user}" />
<property name="dataSource.password" value="${database.password}" />
<property name="dataSource.url" value="${database.url}" />
</bean>
And of course you will have to add the dependency for the pool itself.
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>1.4.0</version>
<scope>compile</scope>
</dependency>
For information on which properties you can set see the HikariCP documentation and Oracle Datasource documentation
Another thing is that your codebase is scattered with lines to measure performance, this really isn't the wisest thing todo nor very efficient. I suggest use a bit of AOP to apply performance measuring to your code, you can then easily remove it in production for instance. Now you have to cleanup your whole codebase.
Spring already has a PerformanceMonitorInterceptor which you can use and configure. If you want more elaborate measuring you can use the JamonPerformanceMonitorInterceptor.
<bean id="performanceInterceptor" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>
<aop:config>
<aop:pointcut id="ourMethods" expression="execution(* com.your.base-package..*.*(..))"/>
<aop:advisor pointcut-ref="ourMethods" advice-ref="performanceInterceptor"/>
</aop:config>
Now you have an unobtrusive way of measuring and logging performance. Keeps your code clean and tidy and you can measure what you want.
Related
I want to use Spring to connect to my local PostgreSQL db. I don't know if it is possible, cause I didn't find any tutorials for this. So is it possible? If yes, please explain me where can I find some fine tutorial. If no, how can I do it? I know I can make it via postgresql jdbc, but I want to do it like in real company.
Of course you can. The database vendor is immaterial. Java hides database details using JDBC.
Here is a Spring tutorial that shows you how to do it in 15 minutes or less.
First you need to create a spring project from https://start.spring.io/ and add postgresql to its dependencies. You will then see it build up in your pom.xml file. Then you have to enter the information of the postgresql database you want to connect to in the application.yml file.
Here is my example.
applicationContext.xml :
<!-- the setting msg -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config/database.properties</value>
</list>
</property>
</bean>
<!-- PostgreSQL datasource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<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>
<!-- ibatis client -->
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:config/SqlMapConfig.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
This question already has an answer here:
UnknownServiceException: Unknown service requested (Hibernate/Spring)
(1 answer)
Closed 7 years ago.
I'm using Spring 4 to set up my stuff that I'll need for using Hibernate 4. I have a SessionFactory autowired into my DAO layer. When I call sessionFactory.getCurrentSession() I get the error:
Exception in thread "MyImporterThread" org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.engine.jdbc.connections.spi.ConnectionProvider]
I've looked at many search results from Google (including a bunch from StackOverflow) on this exception, however none of them has struck me as the solution to my issue.
Here's my configuration:
spring-beans.xml:
<context:property-placeholder location="file:spring.properties" />
<context:component-scan base-package="com.company.scraping" />
<!-- Data Source -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver.class}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- Session Factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.company.scraping" />
<property name="configLocation">
<value>file:scraping.db.hibernate.cfg.xml</value>
</property>
</bean>
<!-- Transaction Stuff -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- beans that are transactional or autowired -->
<bean id="scrapingDao" class="com.company.scraping.dao.ReportsScrapingDaoImpl" />
<bean id="scrapingService" class="com.company.scraping.service.ReportsScrapingServiceImpl" />
spring.properties:
jdbc.driver.class=oracle.jdbc.OracleDriver
jdbc.url=jdbc:oracle:thin:#server:1521:testdb01
jdbc.user=user
jdbc.password=password
scraping.db.hibernate.cfg.xml:
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:oracle:thin:#server:1521:testdb01</property>
<property name="connection.username">user</property>
<property name="connection.password">password</property>
<property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="hibernate.connection.autocommit">true</property>
<property name="hibernate.generate_statistics">false</property>
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="hibernate.show_sql">false</property>
</session-factory>
</hibernate-configuration>
Since this is not a web application, I use ApplicationContext context = new FileSystemXmlApplicationContext(args[0]) to initialize Spring.
My service class is autowired (not shown in the config because I have to type all this out), and contains an autowired instance of the DAO. This is what the DAO looks like:
#org.springframework.stereotype.Repository
#org.springframework.transaction.annotation.Transactional
public class ReportsScrapingDaoImpl implements ReportsScrapingDao
{
#Autowired
#Qualifier("sessionFactory")
private SessionFactory sessionFactory;
#Override
#Transaction(readOnly = true)
public List<Stuff> getAll()
{
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Stuff.class);
... (more code)
}
}
The code bombs out when sessionFactory.getCurrentSession() is called. I've tried using sessionFactory.openSession() as well, but it gave the same results. I'm not sure what's going on here.
I did a last-ditch search and this turned up. Eclipse outputs a compiler warning, complaining that there may be a resource leak because the ApplicationContext is never closed. I added a line at the very end of my main method (after all the Threads had been started) to close the ApplicationContext. Once I got rid of the line that closes the ApplicationContext, the problem went away.
Moral of the story is that your ApplicationContext should not be closed until you no longer need anything from it--so you should probably never close it.
We have a web application implementing Spring MVC 3.2 using JPA as a framework for ORM. Now the problem is that EntityManager is creating a lot of open connections with the database. We want to handle it in such a way that for every query a connection should be established and closed after completion.
As per the spring implementation EntityManager is created once. But the problem here is we in some way want to handle the client connections that EntityManager is creating for querying the database.
Whenever the query is completed in the database, that connection goes into sleep, instead we want to close it once the query returns the result.
DB type: MySQL
My configuration for JPA is :
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.reppify" />
<property name="jpaPropertyMap" ref="jpaPropertyMap" />
<property name="dataSource" ref="dataSourceLocal" />
<property name="persistenceUnitName" value="cron-jpa" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="dataSourceLocal"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
We are using hibernate-jpa-api-2.0 jar as a dependency to the project.
And my JAVA Base DAO implementation for injecting EntityManager looks like:
protected EntityManager entityManager;
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
Please suggest us an optimum solution for the same.
DriverManagerDataSource is not a connections pool, it creates a new connection on every call. This class is useful for testing but you shouldn't use it in production, choose a connection pool instead. There are many connection pools to choose from:
HikariCP
Apache Commons DBCP
c3p0
...
I am using Spring and trying to setup a global transaction spanning over two MS SQL Server DBs. The app is running inside Tomcat 6.
I have these definitions:
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
....
</bean>
<bean id="sessionFactory1"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource1"/>
....
</bean>
<bean id="hibernateTransactionManager1"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory1"/>
</property>
</bean>
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
....
</bean>
<bean id="sessionFactory2"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource2"/>
....
</bean>
<bean id="hibernateTransactionManager2"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory2"/>
</property>
</bean>
Then also, each DAO is linked either to sessionFactory1 or to sessionFactory2.
<bean name="stateHibernateDao" class="com.project.dao.StateHibernateDao">
<property name="sessionFactory" ref="sessionFactory1"/>
</bean>
Also, I recently added these two.
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
<property name="forceShutdown" value="false" />
<property name="transactionTimeout" value="300" />
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
I am trying to programmatically manage the global transaction
(this is some old legacy code and I don't want to change it too
much so I prefer keeping this managed programmatically).
So now I have this UserTransaction ut (injected from Spring), so I call ut.begin(), do some DB/DAO operations to the two DBs through the DAOs, then I call ut.commit().
The thing is that even before the ut.commit() call, I can see the data is already committed to the DBs?!
I don't think Atomikos is aware of my two DBs, their data sources, session factories, etc. I don't think it starts any transactions on them. Looks like they are not enlisted at all in the global transaction.
To me it seems that each DB/DAO operation goes to the SQL Server on its own, so SQL Server creates an implicit transaction for just that DAO/DB operation, applies the operation and commits the implicit the transaction.
But 1) and 2) are just guesses of mine.
My questions:
Do I need to start the two DB transactions myself (but OK, this is what I am currently doing and I am trying to get rid of; that's why I am trying to use Atomikos to start with)?
How I can configure all this correctly so that when I call ut.begin() it begins a global transaction to the two DBs and when I call ut.commit() it commits it?
I haven't played with JTA recently so seems to me I am missing something quite basic here. What is it?
Edit 1
<bean id="globalTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="atomikosUserTransaction"/>
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="allowCustomIsolationLevels" value="true" />
<property name="transactionSynchronization" value="2" />
</bean>
I'm using WebLogic 10.3.3 with Oracle 11g and face a weird problem with Spring Batch as soon as I'm switching from Spring ResourcelessTransactionManager (which is mainly for testing) to the productive DataSourceTransactionManager. First I used WebLogics default driver oracle.jdbc.xa.client.OracleXADataSource but this one fails because Spring can't set the isolation level - this is also documented here.
I'm fine with that since I don't need global transactions anyway so I switched to oracle.jdbc.driver.OracleDriver. Now I'm getting the error message
ORA-01453: SET TRANSACTION must be first statement of transaction
I don't find a lot of information on this, there was a bug but that should have been fixed in Oracle 7 long time ago. It looks like a transaction is started before (?) the actual job gets added to the JobRepository and is not closed properly or something like that.
JobI was able to solve this by setting the Isolation level for all transactions to READ_COMMITTED. By default, Spring sets that to SERIALIZABLE which is very strict (but perfectly fine). This didn't work on my machine although Oracle should support it:
http://www.oracle.com/technetwork/issue-archive/2005/05-nov/o65asktom-082389.html
Here's my code - first for the configuration:
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="dataSource" ref="dataSource" />
<property name="isolationLevelForCreate" value="ISOLATION_READ_COMMITTED" />
</bean>
...and this is for the job itself (simplified):
public class MyFancyBatchJob {
#Transactional(isolation=Isolation.READ_COMMITTED)
public void addJob() {
JobParameters params = new JobParametersBuilder().toJobParameters();
Job job = jobRegistry.getJob("myFancyJob");
JobExecution execution = jobLauncher.run(job, params);
}
}
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" >
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="url" value="jdbc:oracle:thin:<username>/<password>#<host>:1521:<sid>" />
</bean>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="org/springframework/batch/core/schema-drop-oracle10g.sql" />
<jdbc:script location="org/springframework/batch/core/schema-oracle10g.sql" />
</jdbc:initialize-database>
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseType" value="oracle" />
<property name="tablePrefix" value="BATCH_"/>
<property name="isolationLevelForCreate" value="ISOLATION_DEFAULT"/>
</bean>
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
/*for spring batch with oracle 10g and 11g
*/