2017-05-05 47 views
1

時候當我執行:「在交易閒置的」使用Hibernate,Postgres的和吉斯提供商

select * from pg_stat_activity where state ~ 'idle in transact' 

我得到「在交易閒置的」與國家的行數不恰當的。其中一些人閒置了幾天。他們中的大多數,這是從一個服務類執行(休眠5.1.0.Final,吉斯4.1.0)同樣簡單select查詢:

public class FirebaseServiceImpl implements FirebaseService { 

    @Inject 
    private Provider<FirebaseKeyDAO> firebaseKeyDAO; 

    @Override 
    public void sendNotification(User recipient) { 

     List<FirebaseKey> firebaseKeys = firebaseKeyDAO.get().findByUserId(recipient.getId()); 

     final ExecutorService notificationsPool = Executors.newFixedThreadPool(3); 

     for (FirebaseKey firebaseKey : firebaseKeys) 
      notificationsPool.execute(new Runnable() { 

       @Override 
       public void run() { 
        sendNotification(new FirebaseNotification(firebaseKey.getFirebaseKey(), "example"); 
       } 
     }); 

     notificationsPool.shutdown(); 
    } 
} 

DAO方法:

@Override 
@SuppressWarnings("unchecked") 
public List<FirebaseKey> findByUserId(Long userId) { 
    Criteria criteria = getSession().createCriteria(type); 
    criteria.add(Restrictions.eq("userId", userId)); 
    return criteria.list(); 
} 

爲什麼它發生了嗎?如何避免這種情況?

UPDATE

當我在一個單獨的線程中使用吉斯提供商 exampleDAO.get()

事務不COMMITED:

@Inject 
Provider<ExampleDAO> exampleDAO; 

回答

2

通常,當您使用使用pool_mode pgbouncer或其他波爾/會話管理器發生=交易。例如,當客戶端打開一個事務並持有它時,不承諾也不回滾。檢查是否在查詢列中看到DISCARD ALL - 如果你這樣做,because pooler必須放棄共享會話計劃,序列,​​釋放語句等,以避免混合那些池中不同的會話。

在另一方面任何 「正常」 交易給同idle in transaction,如:

2>select now(),pg_backend_pid(); 
       now    | pg_backend_pid 
----------------------------------+---------------- 
2017-05-05 16:53:01.867444+05:30 |   26500 
(1 row) 

如果要檢查它的狀態,我們看到正統idle

t=# select query,state from pg_stat_activity where pid = 26500; 
      query    | state 
--------------------------------+------- 
select now(),pg_backend_pid(); | idle 
(1 row) 

現在我們在session 2 >開始交易: 2>開始; BEGIN

2>select now(),pg_backend_pid(); 
       now    | pg_backend_pid 
----------------------------------+---------------- 
2017-05-05 16:54:15.856306+05:30 |   26500 
(1 row) 

,並檢查pg_stat_statements增益:

t=# select query,state from pg_stat_activity where pid = 26500; 
      query    |  state 
--------------------------------+--------------------- 
select now(),pg_backend_pid(); | idle in transaction 
(1 row) 

它永遠保持這樣直到聲明超時或事務的結束:

2>end; 
COMMIT 
t=# select query,state from pg_stat_activity where pid = 26500; 
query | state 
-------+------- 
end; | idle 
(1 row) 

所以這是很常見的,並確定有它。如果你想避免連接的會話,你必須斷開客戶端連接。但postgres中的連接是昂貴的,所以通常人們嘗試重新使用現有的連接池,所以這樣的狀態出現在pg_stat_activity

+0

有時我有很多長時間運行的查詢'COMMIT'狀態'空閒'。爲什麼會發生?是否值得執行'echo never>/sys/kernel/mm/redhat_transparent_hugepage/enabled',因爲它在https://dba.stackexchange.com/questions/32890/postgresql-pg-stat-activity-shows-commit中提及? – Justas

+0

空閒意味着連接在提交後不會執行任何操作。查詢更改時查詢列發生更改 - 因此顯示上次執行的查詢... –

+0

如果應用程序通過空閒提交達到hibernate.c3p0.max_size限制,則它將停止使用數據庫。 – Justas