Временная схема на соединение?


8

Я пытаюсь перенести свои юнит-тесты с H2 на Postgresql.

В настоящее время H2 предоставляет мне схему в памяти, так что каждое соединение сопоставляется с уникальной схемой, создает таблицы, запускает тест и удаляет схему. Создание и уничтожение схемы автоматически обрабатывается H2.

Модульные тесты запускаются одновременно.

Каков наилучший способ сделать это в Postgresql? В частности,

  1. Как получить уникальную схему для каждого соединения?
    • Должна ли среда тестирования генерировать уникальные имена или есть встроенный механизм для этого?
  2. Как я могу гарантировать, что схема будет отброшена при разрыве соединения?
    • Я не хочу заканчивать висящими схемами, когда модульные тесты убиты.
  3. Какой подход даст максимальную производительность?
    • Мне нужно создавать / отбрасывать десятки схем в секунду.

ОБНОВЛЕНИЕ : я нашел связанный ответ здесь, но он не может отбросить схемы в случае, если процесс, выполняющий модульные тесты, будет убит.

Ответы:


13

pg_temp псевдоним для временной схемы текущего сеанса

Если вы SET search_path TO pg_tempвыполняете тест перед запуском тестов, все должно работать (если явно ничего не ссылается на схему).

Если вы вообще не хотите менять свой сценарий, установите search_pathдля пользователя, который входит в тесты:

> ALTER ROLE testuser SET search_path = pg_temp;

Тогда все, что создает пользователь, будет в pg_temp, если это не указано явно.

Вот пример из psql, показывающий фактическую схему (для этого соединения), в которую разрешается псевдоним:

> SET search_path TO pg_temp;
SET
> create table test();
CREATE TABLE
> \dt test
          List of relations
  Schema   | Name | Type  |  Owner
-----------+------+-------+----------
 pg_temp_4 | test | table | postgres
(1 row)

И, как и следовало ожидать, эта схема отличается для каждого одновременного подключения и исчезает после закрытия подключения.

Обратите внимание, что это также работает для функций, хотя вам придется явно ссылаться на схему pg_temp при их вызове.


Но pg_tempединственная схема правильна? Поэтому, когда я запускаю параллельные модульные тесты, не будут ли они забивать таблицы / данные друг друга?
Гили

1
Нет. Это псевдоним для временной схемы текущего сеанса. Я обновлю ответ с примером.
HBN

Имейте в виду, что если вы просто закроете и откроете соединение, у вас может получиться такая же временная схема, но она будет очищена. Откройте 2 одновременно, чтобы увидеть, как распределяются разные. Вы не можете видеть временную схему другого сеанса, если вы не являетесь суперпользователем.
августа

Конечно, я видел комментарий от вас, спрашивающий о том, когда установить это. В любом случае - это устанавливается для каждой сессии, если вы просто делаете SET search_path; используйте SET LOCAL search_pathдля установки на каждую субтранзакцию, или, если хотите, вы можете установить на уровне пользователя с помощью ALTER USER mytestuser SET search_path = 'pg_temp'или на уровне базы данных с помощьюALTER DATABASE mytestdb SET search_path = 'pg_temp'
hbn

Из любопытства, есть ли способ заставить это работать для функций без явной ссылки на схему? Или это невозможно для pg_tempсхемы?
Гили

3

Вы можете получить имя текущей временной схемы (после создания первой временной таблицы), как показано в добавленной вами ссылке:

SELECT nspname
FROM   pg_namespace
WHERE  oid = pg_my_temp_schema();

Но ваш текущий план все равно не будет иметь большого смысла. Чтобы создать таблицы в текущей временной схеме, просто создайте временные таблицы. Это все. По умолчанию search_pathопределяется так, что временные таблицы видны первыми. Один никогда не нужно схемы-квалифицироваться временными таблицы. Вы никогда не должны иметь для решения текущей временной схемы непосредственно в любом случае - что это деталь реализации.


Согласитесь, это хак, но это может быть значительно проще, чем параметризация кода создания, позволяющего создавать временные таблицы.
августа

Хороший вопрос, за исключением того, что, как упомянул @hbn, я хочу, чтобы модульные тесты и производственный код запускали один и тот же сценарий SQL. Первый должен работать против временной схемы, а второй - нет.
Гили

@hbn, из любопытства, как будет выглядеть параметризованный код создания? Я использую flywaydb.org, и он просто выполняет простые файлы SQL (без переменных). Я, вероятно, не хочу идти по этому пути. Мне просто любопытно, что с этим связано.
Гили

Я никогда не использовал flywaydb. На самом базовом уровне вы можете использовать некоторый текстовый язык (например, Jinja2 в Python) для предварительной обработки сценариев создания, при необходимости добавляя «временный» при создании таблицы. Если вы явно создаете функции, хак get-the-временная схема, вероятно, неизбежен, поскольку (насколько я знаю) вы не можете напрямую создать временную функцию.
августа

@hbn If you're explicitly sequences ...: Думаю, твой последний комментарий содержал опечатку. Что ты хотел сказать между explicitlyи sequences?
Гили

1

Ваши тесты включают транзакции? DDL является транзакционным в PostgreSQL, поэтому, если вы создаете свою схему и таблицы, а затем запускаете свои тесты, все в рамках одной транзакции, которая затем откатывается, схема фактически никогда не фиксируется и не видна другим сеансам.

Вам все равно нужно будет использовать, возможно, уникальное имя для вашей схемы (возможно, включить имя хоста и PID), так как CREATE SCHEMAэто немедленно завершится ошибкой, если схема с одинаковым именем уже существует, и заблокируется, если другой сеанс создал схему с таким же именем в незафиксированная транзакция.

Альтернативой может быть просто использование временных таблиц, если вы можете изменить сценарии создания базы данных для этого.


Хороший трюк, но он не сработает в моем случае, потому что один тест работает с несколькими транзакциями. Каждый метод тестирования - это веб-клиент, который запускает несколько транзакций на стороне сервера. Например, он создает, запрашивает и удаляет пользователя. Каждый вызов является отдельным HTTP-запросом и выполняется в отдельной транзакции.
Гили

Справедливо, мой подход был очень ограничен.
августа

@Gili: Обратите внимание, что эта техника никогда не фиксирует CREATE SCHEMAсебя, единственная, которая может гарантировать, что они исчезнут, когда убит юнит-тест.
Даниэль Верите

0

Я только что получил идею.

Postgresql гарантирует, что сессия не может видеть чужие временные таблицы. Я предполагаю, что это означает, что когда вы создаете временную таблицу, она создает временную схему. Так что, возможно, я мог бы сделать следующее:

  1. Создайте (фиктивную) временную таблицу и найдите ее схему.
  2. Используйте эту схему для теста (создайте таблицы, запустите тест).
  3. Когда соединение закрыто, Postgresql сбросит схему.

Мне не нравится полагаться на детали реализации, но в этом случае это кажется довольно безопасным.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.