'闲置交易'使用Hibernate,Postgres和Guice Provider时

时间:2017-05-05 11:18:51

标签: java postgresql hibernate transactions guice

执行时:

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

在事务处理中,状态为“空闲”的行数不合适。他们中的一些人闲置了几天。其中大多数都是从一个服务类(Hibernate 5.1.0.Final,Guice 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();
}

为什么会这样?怎么避免这个?

更新

当我在单独的线程中使用Guice Provider exampleDAO.get()时,不会提交事务:

@Inject
Provider<ExampleDAO> exampleDAO;

1 个答案:

答案 0 :(得分:2)

当您使用pgbouncer或其他使用pool_mode = transaction的pooler /会话管理器时,通常会发生这种情况。例如,当客户打开一个交易并持有它时,不提交或回滚。检查您是否在查询列中看到DISCARD ALL - 如果您这样做,because pooler必须丢弃共享会话计划,序列,​​解除分配语句等,以避免混合池中不同会话的那些。 / p>

另一方面,任何&#34;正常&#34; transaction提供相同的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