2015-10-13 64 views
3

我目前遇到性能問題在Hibernate中Hibernate的事務管理器性能問題

執行SQL語句(如SELECT * FROM表),大約需要90毫秒與12列

獲取僅10個記錄。然而,對於休眠運行在DAO類下面的Java代碼

List<T> afterGetAll = getSessionFactory().getCurrentSession().createCriteria(type).list(); 

大約需要260〜300毫秒以上語句只執行完成,更不用說額外的執行時間我調用該DAO的服務類。共花費約600〜1000毫秒。我懷疑大部分時間都花在了事務管理上。

我不知道在我的代碼/配置出了問題,我也曾嘗試以下方法,但並不能幫助太多...

  1. 添加的數據源連接池設置
  2. 使用Hibernate本地SQL方法,而不是個createCriteria在DAO類
  3. 啓用延遲加載
  4. Tomcat服務器的增加堆大小
  5. 使用二級緩存提供
  6. @Transactional(readOnly的=真)對於只讀查詢

一些解決方法用於加速操作:

  1. 通過配置EhCacheRegionFactory啓用休眠緩存和一起使第二級緩存。然後在服務器啓動時,我的Web應用程序通過手動觸發服務調用來初始化緩存。在將Hibernate的sql查詢從300〜400ms提取到1〜3ms後,這可以成功地減少到Java類的數據綁定過程。然而,瓶頸是在將事務的點...(見更新#低於2

這裏是我的配置和代碼

Hibernate配置

<bean id="jdbcTemplate" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 
    <property name="driverClass" value="com.mysql.jdbc.Driver" /> 
    <property name="jdbcUrl" value="jdbc:mysql://test /> 
    <property name="user" value="test" /> 
    <property name="password" value="test" /> 
    <property name="maxPoolSize" value="20" /> 
    <property name="minPoolSize" value="5" /> 
    <property name="maxStatements" value="5" /> 
</bean> 

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="jdbcTemplate"></property> 
    <property name="mappingResources"> 
     <list> 
      <value>orm/UserModel.hbm.xml</value> 
      <value>orm/UserToken.hbm.xml</value> 
      <value>orm/RoleModel.hbm.xml</value> 
     </list> 
    </property> 
    <property name="hibernateProperties"> 
     <props> 
     <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> 
     <prop key="hibernate.show_sql">true</prop> 
     <prop key="hibernate.format_sql">true</prop> 
     <prop key="hibernate.use_sql_comments">true</prop> 
     <prop key="hibernate.enable_lazy_load_no_trans">true</prop> 
     <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> 
     <prop key="hibernate.cache.use_second_level_cache">true</prop> 
     <prop key="hibernate.c3p0.minPoolSize">5</prop> 
     <prop key="hibernate.c3p0.maxPoolSize">20</prop> 
     </props> 
    </property> 
</bean> 

<bean id="baseDao" abstract="true" class="com.test.app.project.dao.BaseDAOImpl"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

<bean id="userDao" parent="baseDao" class="com.test.app.project.dao.UserDAOImpl"> 
</bean> 

<bean id="userService" class="com.test.app.project.services.UserServiceImpl"> 
    <property name="userDao" ref="userDao" /> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

DAO類中的所有方法

public <T> List<T> getAll(final Class<T> type) { 
     long startTime = System.nanoTime(); 
     List<T> afterGetAll = getSessionFactory().getCurrentSession().createSQLQuery("SELECT user_id,username,email,is_active FROM app_users") 
       .addScalar("user_id", LongType.INSTANCE) 
       .addScalar("username", StringType.INSTANCE) 
       .addScalar("email", StringType.INSTANCE) 
       .addScalar("is_active", IntegerType.INSTANCE) 
       .setResultTransformer(Transformers.aliasToBean(UserModel.class)).list(); 
     //List<T> afterGetAll = getSessionFactory().getCurrentSession().createCriteria(type).list(); 
     long endTime = System.nanoTime(); 
     long duration = (endTime - startTime); 
     logger.info("============getAll=============== Execution Timestamp: " + duration/1000000 + "milliseconds"); 
     return afterGetAll; 
    } 

服務類調用上述DAO

@Transactional(propagation=Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED) 
@Service 
public class UserServiceImpl implements UserService{ 
... 
    @Override 
    public <T> List<T> getAll(Class<T> type) { 
     List<T> userList = userDao.getAll(type); 
     return userList; 
    } 
... 
} 

任何建議在配置/代碼可以提高性能也受到歡迎。由於第一

更新#1: 啓用休眠的統計數據後,我可以推斷大多數的時間,由於以下統計數據花費不上執行的語句。

2015-10-14 10:45:46 INFO StatisticalLoggingSessionEventListener:275 - Session M 
etrics { 
    298847 nanoseconds spent acquiring 1 JDBC connections; 
    0 nanoseconds spent releasing 0 JDBC connections; 
    914957 nanoseconds spent preparing 1 JDBC statements; 
    335661830 nanoseconds spent executing 1 JDBC statements; 
    0 nanoseconds spent executing 0 JDBC batches; 
    0 nanoseconds spent performing 0 L2C puts; 
    0 nanoseconds spent performing 0 L2C hits; 
    0 nanoseconds spent performing 0 L2C misses; 
    0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 
0 collections); 
    5735 nanoseconds spent executing 1 partial-flushes (flushing a total of 0 en 
tities and 0 collections) 
} 

2015-10-14 10:45:46 INFO AdminOperationController:51 - =======/admin/operation/ 
UserManagement Execution Timestamp:====== 3051milliseconds 

事實證明,執行時間是在執行控制器類調用該服務之間不同的近10倍僅調用DAO和休眠

更新#2

我執行的語句嘗試添加一些毫秒時間戳來追蹤大部分時間花費哪個進程。後來,我發現大部分時間都是在每次服務操作之後將hibernate事務公開爲jdbc事務和提交事務。統計發現日誌如下

2015-10-15 18:00:13,768 DEBUG HibernateTransactionManager:448 - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=o[email protected] [email protected] [email protected] [email protected] [email protected]223d [email protected]c1 [email protected]11 [email protected]4c33 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] 
2015-10-15 18:00:13,847 DEBUG HibernateTransactionManager:516 - Exposing Hibernate transaction as JDBC transaction [ConnectionHandle{url=jdbc:mysql://test, user=test, debugHandle=null, lastResetAgoInSec=18, lastUsedAgoInSec=18, creationTimeAgoInSec=18}] 
2015-10-15 18:00:13,924 DEBUG SQL:109 - 
    /* dynamic native SQL query */ SELECT 
     user_id, 
     username, 
     email, 
     is_active 
    FROM 
     app_users 
2015-10-15 18:00:14,018 TRACE BasicExtractor:78 - extracted value ([user_id] : [BIGINT]) - [43] 
... 
... 
2015-10-15 18:00:14,177 TRACE BasicExtractor:78 - extracted value ([username] : [VARCHAR]) - [username33] 
2015-10-15 18:00:14,178 TRACE BasicExtractor:78 - extracted value ([email] : [VARCHAR]) - [[email protected]] 
2015-10-15 18:00:14,178 TRACE BasicExtractor:78 - extracted value ([is_active] : [INTEGER]) - [0] 
2015-10-15 18:00:14,178 TRACE BasicExtractor:78 - extracted value ([user_id] : [BIGINT]) - [136] 
2015-10-15 18:00:14,179 TRACE BasicExtractor:78 - extracted value ([username] : [VARCHAR]) - [username34] 
2015-10-15 18:00:14,179 TRACE BasicExtractor:78 - extracted value ([email] : [VARCHAR]) - [[email protected]] 
2015-10-15 18:00:14,180 TRACE BasicExtractor:78 - extracted value ([is_active] : [INTEGER]) - [0] 
2015-10-15 18:00:14,283 INFO BaseDAOImpl:117 - ============getAll=============== Execution Timestamp: 433milliseconds 
2015-10-15 18:00:14,284 DEBUG HibernateTransactionManager:759 - Initiating transaction commit 
2015-10-15 18:00:14,286 DEBUG HibernateTransactionManager:580 - Committing Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[[email protected] [email protected] [email protected] [email protected] [email protected]223d [email protected]c1 [email protected]11 [email protected]4c33 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] 
2015-10-15 18:00:14,496 DEBUG HibernateTransactionManager:669 - Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[[email protected] [email protected] [email protected] [email protected] [email protected]223d [email protected]c1 [email protected]11 [email protected]4c33 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction 
2015-10-15 18:00:14,499 INFO StatisticalLoggingSessionEventListener:275 - Session Metrics { 
    21735 nanoseconds spent acquiring 1 JDBC connections; 
    0 nanoseconds spent releasing 0 JDBC connections; 
    10155810 nanoseconds spent preparing 1 JDBC statements; 
    69653167 nanoseconds spent executing 1 JDBC statements; 
    0 nanoseconds spent executing 0 JDBC batches; 
    11795265 nanoseconds spent performing 1 L2C puts; 
    0 nanoseconds spent performing 0 L2C hits; 
    69732 nanoseconds spent performing 1 L2C misses; 
    0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections); 
    31394 nanoseconds spent executing 1 partial-flushes (flushing a total of 0 entities and 0 collections) 
} 
2015-10-15 18:00:14,639 INFO AdminOperationController:49 - =======/admin/operation/UserManagement Execution Timestamp:====== 924milliseconds 

列出了初始化緩存

2015-10-15 18:00:22,410 DEBUG HibernateTransactionManager:516 - Exposing Hibernate transaction as JDBC transaction [ConnectionHandle{url=jdbc:mysql://test, user=test, debugHandle=null, lastResetAgoInSec=22, lastUsedAgoInSec=22, creationTimeAgoInSec=22}] 
2015-10-15 18:00:22,417 INFO BaseDAOImpl:117 - ============getAll=============== Execution Timestamp: 4milliseconds 
2015-10-15 18:00:22,418 DEBUG HibernateTransactionManager:759 - Initiating transaction commit 
2015-10-15 18:00:22,419 DEBUG HibernateTransactionManager:580 - Committing Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[[email protected] [email protected] [email protected] [email protected] [email protected]39b0 [email protected]94 [email protected]4 [email protected]2ad8 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] 
2015-10-15 18:00:22,625 DEBUG HibernateTransactionManager:669 - Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[[email protected] [email protected] [email protected] [email protected] [email protected]39b0 [email protected]94 [email protected]4 [email protected]2ad8 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction 
2015-10-15 18:00:22,627 INFO StatisticalLoggingSessionEventListener:275 - Session Metrics { 
    19621 nanoseconds spent acquiring 1 JDBC connections; 
    0 nanoseconds spent releasing 0 JDBC connections; 
    0 nanoseconds spent preparing 0 JDBC statements; 
    0 nanoseconds spent executing 0 JDBC statements; 
    0 nanoseconds spent executing 0 JDBC batches; 
    0 nanoseconds spent performing 0 L2C puts; 
    2170444 nanoseconds spent performing 1 L2C hits; 
    0 nanoseconds spent performing 0 L2C misses; 
    0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections); 
    19018 nanoseconds spent executing 1 partial-flushes (flushing a total of 0 entities and 0 collections) 
} 
2015-10-15 18:00:22,766 INFO AdminOperationController:49 - =======/admin/operation/UserManagement Execution Timestamp:====== 425milliseconds 

有誰可以建議我應該如何改善這種情況呢?

+0

您是否嘗試過設置@Transactional(readOnly = true)以上公開列表 getAll(類別類型)? –

+0

你的setResultTransformer調用真的是強制性的嗎?通用方法呢? (可以將ResultTransformer應用於本機SQL查詢,例如,這允許返回非管理實體)。 –

+0

@AndréBlaszczyk 我也嘗試了@Transactional(readOnly = true)對於那些只讀查詢,但沒有運氣 setResultTransformer調用不是必需的,只是一些實驗。我原來的代碼是在下面評論的代碼...但是在性能方面沒有太大的區別。 – SerMintt

回答

0

終於解決了這個問題。 除了配置解決方案(請參閱我編輯的文章,我使用緩存初始化),我重構我的代碼儘可能在一個事務服務方法中進行適當的DAO操作(在此之前,我的事務服務只有非常簡化的方法,即我可能需要調用幾個交易服務方法一個工作流程(如註冊新用戶),這是非常昂貴的這樣做。

它提高我的表現更進一步。

正如我們看到的,在我的帖子更新#2 ,瓶頸是交易提交,可能是數據庫服務器問題,現在我把db改成localhost,速度從400〜500ms進一步提升到20ms

2

請找一些建議:

  1. 設置hibernate.show_sql爲「假」,確保Hibernate日誌是在可能的最低記錄水平運行。
  2. 定義爲延遲加載作爲首選關聯加載策略。
  3. 設置@Transactional(readOnly = true)關於查詢和標準,當返回的對象將永遠不會被修改。
  4. 大多數查詢不會從緩存中受益,所以默認情況下查詢不會被緩存。要啓用緩存,請致電Query.setCacheable(true)
  5. 您可以激活Hibernate統計信息來分析性能問題(屬性hibernate.generate_statistics設置爲true)。
  6. 確認您在桌上有索引
+0

謝謝。我試圖激活Hibernate Statistics。這似乎是由於交易管理器問題(在我的文章中更新) – SerMintt