当我执行时:
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;
最佳答案
当您使用 pgbouncer 或其他使用 pool_mode = transaction 的 pooler/session 管理器时,通常会发生这种情况。例如,当客户打开一个事务并持有它时,既不提交也不回滚。检查您是否在查询列中看到 DISCARD ALL
- 如果是这种情况,because pooler 必须丢弃共享的 session 计划、序列、解除分配语句等,以避免在池中混合不同 session 的那些。
另一方面,任何“正常”交易都会产生相同的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>开始;
开始
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)
所以拥有它是很常见的。如果你想避免连接的 session ,你必须断开客户端。但是 postgres 中的连接是昂贵的,所以通常人们会尝试使用池重用现有的连接,所以这样的状态出现在 pg_stat_activity
关于java - 使用 Hibernate、Postgres 和 Guice Provider 时“事务中空闲”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43803627/