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

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';

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


当前回答

如果您正在使用docker运行postgresql服务器,请重新启动容器。

其他回答

如果您正在使用docker运行postgresql服务器,请重新启动容器。

在macOS中尝试通过控制台使用以下命令重新启动postgresql数据库:

brew services restart postgresql

在终端试试这个命令:

ps -ef | grep postgres

你会看到:

501 1445 3645 0 12:05AM 0:00.03 postgres: sasha dbname (本地)闲置

第三个数字(3645)是PID。

你可以删除这个

sudo kill -9 3645

然后启动PostgreSQL连接。

手动启动:

pg_ctl -D /usr/local/var/postgres start

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

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';

它肯定会起作用。

在我的情况下,我使用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);
    }
  }