每当我尝试删除数据库,我得到以下错误:

ERROR:  database "pilot" is being accessed by other users
DETAIL:  There is 1 other session using the database.

当我使用:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB';

我终止了来自该数据库的连接,但如果我试图在此之后删除数据库,则有人以某种方式自动连接到该数据库并给出此错误。那是什么? 除了我,没人用这个数据库。


当前回答

每当我尝试删除数据库时,我得到:

ERROR:  database "pilot" is being accessed by other users
DETAIL:  There is 1 other session using the database.

首先你需要撤销

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

然后使用:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB';

它肯定会起作用。

其他回答

解决方案: 1. 关闭Pg服务器 2. 它将断开所有活动连接 3.重启Pg服务器 4. 试试你的命令

REVOKE CONNECT将不阻止来自db所有者或超级用户的连接。因此,如果您不希望任何人连接db, follow命令可能会有用。

alter database pilot allow_connections = off;

然后使用:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'pilot';

这意味着另一个用户正在访问数据库。简单地重启PostgreSQL。这个命令就可以了

root@kalilinux:~#sudo service postgresql restart

然后尝试删除数据库:

postgres=# drop database test_database;

这样就可以了。

在Postgresql 13中更新

您可以使用此命令强制删除数据库,从而断开连接到它的每个用户/应用程序。

DROP DATABASE db_name WITH (FORCE)

你可以查看说明书了解更多信息。

力, 尝试终止到目标数据库的所有现有连接。如果目标数据库中存在准备好的事务、活动逻辑复制插槽或订阅,则它不会终止。

在我的情况下,我使用AWS红移(基于Postgres)。 它似乎没有其他连接到DB,但我得到这个相同的错误。

ERROR:  database "XYZ" is being accessed by other users

在我的例子中,似乎数据库集群仍在对数据库进行一些处理,虽然没有其他外部/用户连接,但数据库仍在内部使用。我通过运行以下命令发现了这一点:

SELECT * FROM stv_sessions;

所以我的黑客是写一个循环在我的代码,寻找行与我的数据库名称。(当然循环不是无限的,是一个休眠循环等等)

SELECT * FROM stv_sessions where db_name = 'XYZ';

如果找到行,继续逐个删除每个PID。

SELECT pg_terminate_backend(PUT_PID_HERE);

如果没有找到行,则继续删除数据库

DROP DATABASE XYZ;

注意:在我的例子中,我正在编写Java单元/系统测试,这可以被认为是可以接受的。这对于产品代码是不可接受的。


这里是完整的破解,在Java(忽略我的测试/实用程序类)。

  int i = 0;
  while (i < 10) {
    try {
      i++;
      logStandardOut("First try to delete session PIDs, before dropping the DB");
      String getSessionPIDs = String.format("SELECT stv_sessions.process, stv_sessions.* FROM stv_sessions where db_name = '%s'", dbNameToReset);
      ResultSet resultSet = databaseConnection.execQuery(getSessionPIDs);
      while (resultSet.next()) {
        int sessionPID = resultSet.getInt(1);
        logStandardOut("killPID: %s", sessionPID);
        String killSessionPID = String.format("select pg_terminate_backend(%s)", sessionPID);
        try {
          databaseConnection.execQuery(killSessionPID);
        } catch (DatabaseException dbEx) {
          //This is most commonly when a session PID is transient, where it ended between my query and kill lines
          logStandardOut("Ignore it, you did your best: %s, %s", dbEx.getMessage(), dbEx.getCause());
        }
      }

      //Drop the DB now
      String dropDbSQL = String.format("DROP DATABASE %s", dbNameToReset);
      logStandardOut(dropDbSQL);
      databaseConnection.execStatement(dropDbSQL);
      break;
    } catch (MissingDatabaseException ex) {
      //ignore, if the DB was not there (to be dropped)
      logStandardOut(ex.getMessage());
      break;
    } catch (Exception ex) {
      logStandardOut("Something went wrong, sleeping for a bit: %s, %s", ex.getMessage(), ex.getCause());
      sleepMilliSec(1000);
    }
  }