java - 使用 Hibernate、Postgres 和 Guice Provider 时“事务中空闲”

标签 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;

最佳答案

当您使用 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/

相关文章:

php - 插入前检查 PostgreSQL 表

java - 调用 query.list() 后 Hibernate session 关闭

java - Hibernate:奇怪的异常

java - 用于双向 Hibernate 关联的 MapStruct 自定义列表映射

java单例模式,所有变量都应该是类变量吗?

java - 使用java中的方法

java - Java中将2个ArrayList浅拷贝到1个

ruby-on-rails - 保存失败后 Rails 不回滚事务()

java - 如何使用 smslib 中的 smsserver.java?我已经阅读了文档

sql - 删除 "column does not exist"