Запуск PostgreSQL только в памяти - PullRequest
80 голосов
/ 24 октября 2011

Я хочу запустить небольшую базу данных PostgreSQL, которая работает только в памяти, для каждого написанного мной модульного теста. Например:

@Before
void setUp() {
    String port = runPostgresOnRandomPort();
    connectTo("postgres://localhost:"+port+"/in_memory_db");
    // ...
}

В идеале в систему управления версиями должен быть включен один исполняемый файл postgres, который будет использоваться модульным тестом.

Что-то вроде HSQL, но для postgres. Как я могу это сделать?

Могу ли я получить такую ​​версию Postgres? Как я могу проинструктировать его не использовать диск?

Ответы [ 7 ]

66 голосов
/ 24 октября 2011

Или вы можете создать TABLESPACE в ramfs / tempfs и создать все свои объекты там.
Недавно мне указали на статью о том, как сделать это в Linux .

Внимание

Это может поставить под угрозу целостность всего вашего всего кластера баз данных .
Прочитайте добавленное предупреждение в руководстве.
Так что это только вариант для расходных данных.

Для юнит-тестирования должно работать просто отлично. Если вы работаете с другими базами данных на том же компьютере, обязательно используйте отдельный кластер баз данных (который имеет собственный порт) для обеспечения безопасности.

64 голосов
/ 16 июня 2014

(Перемещение моего ответа из Использование PostgreSQL в памяти и обобщение его):

Вы не можете запустить Pg в процессе, в памяти

Я не могу понять, как запустить базу данных Postgres в памяти для тестирования. Возможно ли это?

Нет, это невозможно. PostgreSQL реализован на C и скомпилирован в код платформы. В отличие от H2 или Derby, вы не можете просто загрузить jar и запустить его как одноразовую БД в памяти.

В отличие от SQLite, который также написан на C и скомпилирован в код платформы, PostgreSQL также не может быть загружен в процессе. Требуется несколько процессов (по одному на соединение), потому что это многопроцессорная, а не многопоточная архитектура. Требование многопроцессорности означает, что вы должны запустить почтмейстер как самостоятельный процесс.

Вместо этого: предварительно настроить соединение

Я предлагаю просто написать свои тесты, чтобы ожидать, что определенное имя хоста / имя пользователя / пароль сработает, и иметь тестовую привязку CREATE DATABASE одноразовой базы данных, затем DROP DATABASE в конце цикла. Получить сведения о соединении с базой данных из файла свойств, целевых свойств сборки, переменной среды и т. Д.

Безопасно использовать существующий экземпляр PostgreSQL, в котором у вас уже есть базы данных, в которых вы заинтересованы, при условии, что пользователь, которого вы предоставляете для своих модульных тестов, является , а не суперпользователем, только пользователь с правами CREATEDB , В худшем случае вы создадите проблемы с производительностью в других базах данных. По этой причине я предпочитаю запускать полностью изолированную установку PostgreSQL для тестирования.

Вместо этого: Запустите бесплатный экземпляр PostgreSQL для тестирования

В качестве альтернативы, если вы действительно заинтересованы, вы можете попросить, чтобы ваш тестовый жгут обнаружил файлы initdb и postgres, запустить initdb, чтобы создать базу данных, изменить pg_hba.conf на trust, запустите postgres, чтобы запустить его на произвольном порту, создать пользователя, создать БД и запустить тесты . Вы даже можете связать двоичные файлы PostgreSQL для нескольких архитектур в jar и распаковать их для текущей архитектуры во временный каталог перед запуском тестов.

Лично я думаю, что это большая боль, которую следует избегать; гораздо проще просто настроить тестовую БД. Однако с появлением поддержки include_dir в postgresql.conf стало немного легче; теперь вы можете просто добавить одну строку, а затем написать сгенерированный файл конфигурации для всех остальных.

Ускоренное тестирование с PostgreSQL

Для получения дополнительной информации о том, как безопасно улучшить производительность PostgreSQL для целей тестирования, см. Подробный ответ, который я написал по этой теме ранее: Оптимизация PostgreSQL для быстрого тестирования

диалект PostgreSQL от H2 не является верной заменой

Некоторые люди вместо этого используют базу данных H2 в режиме диалекта PostgreSQL для запуска тестов. Я думаю, что это почти так же плохо, как люди из Rails, использующие SQLite для тестирования и PostgreSQL для производственного развертывания.

H2 поддерживает некоторые расширения PostgreSQL и эмулирует диалект PostgreSQL. Однако это всего лишь эмуляция. Вы найдете области, где H2 принимает запрос, а PostgreSQL нет, где поведение отличается и т. Д. . Вы также найдете множество мест, где PostgreSQL поддерживает то, что H2 просто не может сделать - например, оконные функции на момент написания.

Если вы понимаете ограничения этого подхода и ваш доступ к базе данных прост, H2 может быть в порядке. Но в этом случае вы, вероятно, лучший кандидат на ORM, который абстрагирует базу данных, потому что вы все равно не используете ее интересные функции - и в этом случае вам больше не нужно заботиться о совместимости базы данных.

Табличные пространства не являются ответом!

Не не использовать табличное пространство для создания базы данных "в памяти". Это не только не нужно, так как в любом случае это существенно не повлияет на производительность, но также является отличным способом нарушить доступ к любому другому, что может вас заинтересовать в той же установке PostgreSQL. Документация 9.4 теперь содержит следующее предупреждение :

ПРЕДУПРЕЖДЕНИЕ

Несмотря на то, что он расположен вне основного каталога данных PostgreSQL, Табличные пространства являются неотъемлемой частью кластера базы данных и не могут быть рассматривается как автономный набор файлов данных. Они зависимы на метаданные, содержащиеся в главном каталоге данных, и, следовательно, не может быть прикрепленным к другому кластеру базы данных или резервным копированием по отдельности. Точно так же, если вы потеряете табличное пространство (удаление файла, сбой диска, и т. д.), кластер базы данных может стать нечитаемым или не сможет запуститься. Размещение табличного пространства во временной файловой системе, как риск виртуального диска Надежность всего кластера.

потому что я заметил, что слишком много людей делают это и сталкиваются с проблемами.

(Если вы сделали это, вы можете mkdir отсутствующий каталог табличного пространства, чтобы PostgreSQL мог снова запуститься, затем DROP отсутствующие базы данных, таблицы и т. Д. Лучше просто не делать этого.)

36 голосов
/ 24 октября 2011

Это невозможно с Postgres.Он не предлагает обработчик внутри процесса / в памяти, такой как HSQLDB или MySQL.

Если вы хотите создать автономную среду, вы можете поместить двоичные файлы Postgres в SVN (ноэто больше, чем просто один исполняемый файл).

Вам нужно будет запустить initdb , чтобы настроить тестовую базу данных, прежде чем что-либо делать с этим.Это можно сделать из командного файла или с помощью Runtime.exec ().Но обратите внимание, что initdb не является чем-то быстрым.Вы определенно не хотите запускать это для каждого теста.Вы можете избежать запуска этого до вашего набора тестов, хотя.

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

Вы можете заново создать тестовую базу данных, используя базу данных шаблонов, что делает ее создание довольно быстрым ( лот быстрее, чем запуск initdb для каждого запуска теста)

23 голосов
/ 21 сентября 2017

Теперь можно запускать экземпляр PostgreSQL в памяти в ваших тестах JUnit через встроенный компонент PostgreSQL из OpenTable: https://github.com/opentable/otj-pg-embedded.

Добавляя зависимость к встроенной библиотеке otj-pg (https://mvnrepository.com/artifact/com.opentable.components/otj-pg-embedded), вы можете запускать и останавливать свой собственный экземпляр PostgreSQL в ваших хуках @Before и @Afer:

EmbeddedPostgres pg = EmbeddedPostgres.start();

Они даже предлагают правило JUnit для автоматического запуска и остановки JUnit на вашем сервере баз данных PostgreSQL:

@Rule
public SingleInstancePostgresRule pg = EmbeddedPostgresRules.singleInstance();
10 голосов
/ 09 сентября 2017

Вы можете использовать TestContainers для ускорения док-контейнера PosgreSQL для тестов: http://testcontainers.viewdocs.io/testcontainers-java/usage/database_containers/

TestContainers предоставляют JUnit @ Rule / @ ClassRule : этот режимзапускает базу данных внутри контейнера перед вашими тестами и разбирает ее потом.

Пример:

public class SimplePostgreSQLTest {

    @Rule
    public PostgreSQLContainer postgres = new PostgreSQLContainer();

    @Test
    public void testSimple() throws SQLException {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(postgres.getJdbcUrl());
        hikariConfig.setUsername(postgres.getUsername());
        hikariConfig.setPassword(postgres.getPassword());

        HikariDataSource ds = new HikariDataSource(hikariConfig);
        Statement statement = ds.getConnection().createStatement();
        statement.execute("SELECT 1");
        ResultSet resultSet = statement.getResultSet();

        resultSet.next();
        int resultSetInt = resultSet.getInt(1);
        assertEquals("A basic SELECT query succeeds", 1, resultSetInt);
    }
}
4 голосов
/ 24 декабря 2018

В настоящее время существует версия PostgreSQL в памяти от русской поисковой компании Yandex: https://github.com/yandex-qatools/postgresql-embedded

Он основан на процессе встраивания Flapdoodle OSS.

Пример использования (со страницы github):

// starting Postgres
final EmbeddedPostgres postgres = new EmbeddedPostgres(V9_6);
// predefined data directory
// final EmbeddedPostgres postgres = new EmbeddedPostgres(V9_6, "/path/to/predefined/data/directory");
final String url = postgres.start("localhost", 5432, "dbName", "userName", "password");

// connecting to a running Postgres and feeding up the database
final Connection conn = DriverManager.getConnection(url);
conn.createStatement().execute("CREATE TABLE films (code char(5));");

Я использую это некоторое время. Хорошо работает.

ОБНОВЛЕНО : этот проект больше не поддерживается активно

Please be adviced that the main maintainer of this project has successfuly 
migrated to the use of Test Containers project. This is the best possible 
alternative nowadays.
2 голосов
/ 11 июня 2013

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

...