'idle in transaction' when using Hibernate, Postgres and Guice Provider

我的未来我决定 提交于 2019-12-11 09:11:55

问题


When I execute:

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

I get inappropriate number of rows with state 'idle in transaction'. Some of them idle for a few days. Most of them, are the same simple select query which are executed from one service class (Hibernate 5.1.0.Final, Guice 4.1.0):

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 method:

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

Why does it happen? How to avoid this?

UPDATE

Transactions are not commited when I use Guice Provider exampleDAO.get() in a separate thread:

@Inject
Provider<ExampleDAO> exampleDAO;

回答1:


It usually happens when you use pgbouncer or other pooler/session manager that uses pool_mode = transaction. Eg when client opens a transaction and holds it, not committing nor rolling back. Check if you see DISCARD ALL in query column - if you do this is the case, because pooler has to discard shared session plans, sequences, deallocate statements etc to avoid mixing those for different sessions in pool.

On the other hand any "normal" transaction gives same idle in transaction, eg:

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

if we check its state we see orthodox idle:

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

now we start transaction on session 2 >: 2>begin; BEGIN

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

and check pg_stat_statements gain:

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

It will remain this way until statement timeout or end of transaction:

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

So it is quite common and ok to have it. If you want to avoid connected sessions, you have to disconnect client. But connection in postgres is expensive, so usually people try reuse existing connections with pool, and so such states appear in pg_stat_activity



来源:https://stackoverflow.com/questions/43803627/idle-in-transaction-when-using-hibernate-postgres-and-guice-provider

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!