web-dev-qa-db-ja.com

メモリでのみPostgreSQLを実行する

私が書いたユニットテストごとに、メモリのみで実行される小さなPostgreSQLデータベースを実行したいと思います。例えば:

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

理想的には、単一のpostgres実行可能ファイルをバージョン管理にチェックインして、ユニットテストで使用するようにします。

HSQLに似ていますが、postgres用です。どうやってやるの?

このようなPostgresバージョンを入手できましたか?ディスクを使用しないように指示するにはどうすればよいですか?

84
Chi-Lan

これはPostgresでは不可能です。 HSQLDBやMySQLのようなインプロセス/インメモリエンジンは提供しません。

自己完結型の環境を作成する場合は、PostgresバイナリをSVNに配置できます(ただし、実行可能ファイルは1つだけではありません)。

これで何かをする前に initdb を実行してテストデータベースをセットアップする必要があります。これは、バッチファイルから、またはRuntime.exec()を使用して実行できます。ただし、initdbは高速なものではないことに注意してください。あなたは間違いなく各テストに対してそれを実行したくないでしょう。ただし、テストスイートの前にこれを実行して逃げるかもしれません。

ただし、これは実行できますが、テストを実行する前にテストデータベースを再作成する専用のPostgresインストールをお勧めします。

テンプレートデータベースを使用してテストデータベースを再作成できます。テンプレートデータベースを使用すると、テストを実行するたびにinitdbを実行するよりも高速にlot作成できます。

38

(私の答えを in-memory PostgreSQLを使用 から移動して一般化):

インプロセスでインメモリを実行することはできません

テストのためにインメモリPostgresデータベースを実行する方法がわかりません。出来ますか?

いいえ、できません。 PostgreSQLはCで実装され、プラットフォームコードにコンパイルされます。 H2やDerbyとは異なり、jarをロードして、それを使い捨てのインメモリDBとして起動することはできません。

Cで記述され、プラットフォームコードにコンパイルされるSQLiteとは異なり、PostgreSQLもインプロセスで読み込むことはできません。マルチスレッドではなく、マルチプロセッシングアーキテクチャであるため、複数のプロセス(接続ごとに1つ)が必要です。マルチプロセッシングの要件は、mustポストマスターをスタンドアロンプ​​ロセスとして起動することを意味します。

代わりに:接続を事前設定します

特定のホスト名/ユーザー名/パスワードが機能することを期待してテストを作成し、テストハーネスCREATE DATABASEスローアウェイデータベース、実行の最後にDROP DATABASEを作成することをお勧めします。プロパティファイルからデータベース接続の詳細を取得し、ターゲットプロパティ、環境変数などを構築します。

単体テストに指定するユーザーがnotスーパーユーザーである限り、すでに気にしているデータベースがある既存のPostgreSQLインスタンスを使用しても安全です、CREATEDB権限を持つユーザーのみ。最悪の場合、他のデータベースでパフォーマンスの問題が発生します。そのため、テストのために完全に分離されたPostgreSQLインストールを実行することを好みます。

代わりに:テスト用に使い捨てのPostgreSQLインスタンスを起動します

あるいは、本当に熱心なら テストハーネスにinitdbpostgresのバイナリを見つけさせる、initdbを実行してデータベースを作成し、pg_hba.conftrustに変更し、postgresを実行してランダムポートで起動し、ユーザーを作成し、DBを作成して、テスト 。テストを実行する前に、jar内の複数のアーキテクチャ用のPostgreSQLバイナリをバンドルし、現在のアーキテクチャ用のものを一時ディレクトリに解凍することもできます。

個人的には、それは避けるべき大きな痛みだと思います。テストDBを構成するだけの方が簡単です。ただし、include_dirpostgresql.confサポートの出現により、少し簡単になりました。これで、1行追加するだけで、残りのすべてについて生成された構成ファイルを作成できます。

PostgreSQLによる高速テスト

テスト目的でPostgreSQLのパフォーマンスを安全に改善する方法の詳細については、このトピックで以前に書いた詳細な回答を参照してください: Optimise高速テスト用のPostgreSQL

H2のPostgreSQL方言は真の代替ではありません

代わりに、PostgreSQLダイアレクトモードでH2データベースを使用してテストを実行する人もいます。これはRailsテストにSQLiteを使用し、実稼働展開にPostgreSQLを使用している人々とほぼ同じくらい悪いと思います。

H2はいくつかのPostgreSQL拡張機能をサポートし、PostgreSQLの方言をエミュレートします。ただし、それだけです-エミュレーション。 H2はクエリを受け入れますが、PostgreSQLは受け入れない、動作が異なるエリアなどを見つけるでしょう 。また、執筆時点でウィンドウ関数のように、PostgreSQLがH2ではできないことをサポートしている場所もたくさんあります。

このアプローチの制限を理解し、データベースへのアクセスが簡単な場合、H2は問題ないかもしれません。しかし、その場合は、おそらく興味深い機能を使用していないため、データベースを抽象化するORMのより良い候補です。その場合、データベースの互換性をこれ以上気にする必要はありません。

テーブルスペースは答えではありません!

notは、テーブルスペースを使用して「メモリ内」データベースを作成します。とにかくパフォーマンスを大幅に向上させないため不要であるだけでなく、同じPostgreSQLインストールで気になる他のユーザーへのアクセスを中断する素晴らしい方法でもあります。 9.4のドキュメントには、次の警告が含まれるようになりました

[〜#〜] warning [〜#〜]

メインのPostgreSQLデータディレクトリの外部にありますが、テーブルスペースはデータベースクラスターの不可欠な部分であり、データファイルの自律的なコレクションとして扱うことはできません。これらはメインデータディレクトリに含まれるメタデータに依存しているため、別のデータベースクラスターに接続したり、個別にバックアップしたりすることはできません。同様に、表領域が失われた場合(ファイルの削除、ディスクの障害など)、データベースクラスターが読み取り不能になるか、起動できなくなる可能性があります。 ramdiskのような一時ファイルシステムにテーブルスペースを配置すると、クラスター全体の信頼性が低下します。

あまりにも多くの人がこれをしてトラブルに直面していることに気づいたからです。

(これを行った場合、mkdir不足しているテーブルスペースディレクトリを使用してPostgreSQLを再起動し、DROP不足しているデータベース、テーブルなどを使用できます。

67
Craig Ringer

または、ramfs/tempfsで [〜#〜] tablespace [〜#〜] を作成し、そこにすべてのオブジェクトを作成できます。
最近、 Linuxでそれを正確に行うことに関する記事 を指摘されました。

警告

これは、データベースクラスター全体の整合性を危険にさらす可能性があります
マニュアルに追加された警告をお読みください。
したがって、これは消耗データのオプションにすぎません。

unit-testingの場合、問題なく動作するはずです。同じマシン上で他のデータベースを実行している場合は、安全のために、個別のデータベースクラスター(独自のポートを持つ)を使用してください。

66

OpenTableの埋め込みPostgreSQLコンポーネントを使用して、JUnitテストでPostgreSQLのメモリ内インスタンスを実行できるようになりました: https://github.com/opentable/otj-pg-embedded

依存関係をotj-pg-embeddedライブラリに追加することで( https://mvnrepository.com/artifact/com.opentable.components/otj-pg-embedded )、独自のインスタンスを起動および停止できます。 @Beforeおよび@AferフックでのPostgreSQLの例:

EmbeddedPostgres pg = EmbeddedPostgres.start();

さらに、JUnitがPostgreSQLデータベースサーバーを自動的に開始および停止するJUnitルールを提供します。

@Rule
public SingleInstancePostgresRule pg = EmbeddedPostgresRules.singleInstance();
23
Rubms

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);
    }
}
11
Andrejs

現在、ロシア語検索会社のYandexという名前のPostgreSQLのメモリ内バージョンがあります。 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));");

しばらく使用しています。うまくいきます。

[〜#〜] updated [〜#〜]:このプロジェクトはもう積極的にメンテナンスされていません

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.
4
akvyalkov

また、PostgreSQLの構成設定(質問や受け入れられた回答 here で詳しく説明されている設定など)を使用して、必ずしもメモリ内データベースに頼らずにパフォーマンスを達成することもできます。

2
Dan