Exécuter PostgreSQL en mémoire uniquement

je veux lancer une petite base de données PostgreSQL qui fonctionne en mémoire uniquement, pour chaque test unitaire que j'écris. Par exemple:

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

idéalement, je vais faire vérifier un seul exécutable postgres dans le contrôle de version, que le test de l'unité utilisera.

quelque chose comme HSQL , mais pour postgres. Comment puis-je le faire?

puis-je avoir une telle version de Postgres? Comment puis-je demander de ne pas utiliser le disque?

67
demandé sur Erwin Brandstetter 2011-10-24 11:58:30

6 réponses

ce n'est pas possible avec Postgres. Il n'offre pas de moteur in-process/in-memory comme HSQLDB ou MySQL.

si vous voulez créer un environnement autonome, vous pouvez mettre les binaires Postgres dans SVN (mais c'est plus qu'un simple exécutable).

vous devrez exécuter initdb pour configurer votre base de données de test avant de pouvoir faire quoi que ce soit avec cela. Cela peut être fait à partir d'un fichier de commandes ou à l'aide d'Exécution.exec (). Mais notez qu'initdb n'est pas quelque chose de rapide. Vous ne voudrez certainement pas exécuter cela pour chaque test. Vous pourriez vous en tirer en faisant ça avant votre test-suite.

cependant bien que cela puisse être fait, je recommande d'avoir une installation Postgres dédiée où vous recréez simplement votre base de données de test avant d'exécuter vos tests.

vous pouvez recréer la base de données test en utilisant un modèle de base de données qui fait la création assez rapide (un lot plus rapide que l'exécution initdb pour chaque essai)

31
répondu a_horse_with_no_name 2011-10-24 08:20:13

ou vous pouvez créer un TABLESPACE dans un ramfs / tempfs et y créer tous vos objets.

J'ai récemment été pointé vers un article à propos de faire exactement cela sur Linux .

avertissement

cela peut mettre en danger l'intégrité de votre cluster entier de base de données .

Lire l'Avertissement ajouté dans le manuel.

Ce n'est donc qu'une option pour les données non réutilisables.

Pour tests unitaires il devrait fonctionner très bien. Si vous exécutez d'autres bases de données sur la même machine, assurez-vous d'utiliser un cluster de base de données (qui a son propre port) pour être sûr.

62
répondu Erwin Brandstetter 2015-10-16 01:27:53

(déplacer ma réponse de en utilisant en mémoire PostgreSQL et la généraliser):

Vous ne pouvez pas exécuter Pg, en mémoire

Je ne sais pas comment exécuter en mémoire La base de données Postgres pour le test. Est-il possible?

non, ce n'est pas possible. PostgreSQL est implémenté en C et compilé en code plateforme. Contrairement à H2 ou Derby vous ne pouvez pas juste charger le jar et lancez-le en tant que DB mémoire.

contrairement à SQLite, qui est aussi écrit en C et compilé avec le code de la plate-forme, PostgreSQL ne peut pas non plus être chargé en cours de traitement. Il nécessite plusieurs processus (un par connexion) parce que c'est une architecture multiprocessing, pas multithreading. L'exigence de multiprocesseur signifie que vous doit lancer le postmaster comme un processus autonome.

au lieu de: préconfigure une connexion

je suggère simplement d'écrire vos tests pour vous attendre à ce qu'un nom d'hôte/nom d'utilisateur/mot de passe particulier fonctionne, et d'avoir le harnais de test CREATE DATABASE une base de données throwaway, puis DROP DATABASE à la fin de la course. Obtenez les détails de connexion à la base de données à partir d'un fichier de propriétés, de propriétés cibles de construction, de variables d'environnement, etc.

il est sûr d'utiliser une instance PostgreSQL existante dans laquelle vous avez déjà des bases de données auxquelles vous tenez tant que l'utilisateur vous fournissez à votre unité des tests est pas un super-utilisateur, seulement un utilisateur avec des droits CREATEDB . Au pire, vous créerez des problèmes de performance dans les autres bases de données. Je préfère lancer une installation PostgreSQL complètement isolée pour tester pour cette raison.

à la place: lancer une instance PostgreSQL pour tester

alternativement, si vous êtes vraiment keen vous pourriez avoir votre harnais d'essai Localisez les binaires initdb et postgres , Lancez initdb pour créer une base de données, modifiez pg_hba.conf en trust , Lancez postgres pour le démarrer sur un port aléatoire, créez un utilisateur, créez un DB, et lancez les tests . Vous pouvez même regrouper les binaires PostgreSQL pour plusieurs architectures dans un bocal et déballer ceux de l'architecture courante dans un répertoire temporaire avant d'exécuter les tests.

personnellement, je pense que c'est une douleur majeure que devrait être évité; il est beaucoup plus facile d'avoir juste un test DB configuré. Cependant, c'est devenu un peu plus facile avec l'avènement du support include_dir dans postgresql.conf ; maintenant vous pouvez juste ajouter une ligne, puis écrire un fichier de configuration généré pour tout le reste.

test plus rapide avec PostgreSQL

pour plus d'informations sur la façon de en toute sécurité améliorer la performance de PostgreSQL à des fins de test, voir une réponse détaillée I a écrit sur ce sujet plus tôt: optimiser PostgreSQL pour les tests rapides

le dialecte PostgreSQL de H2 n'est pas un vrai substitut

certaines personnes utilisent plutôt la base de données H2 en mode dialecte PostgreSQL pour exécuter des tests. Je pense que c'est presque aussi mauvais que les gens de Rails utilisant SQLite pour les tests et PostgreSQL pour le déploiement de la production.

H2 supporte certaines extensions PostgreSQL et émule le PostgreSQL dialecte. Cependant, c'est juste que - une émulation. vous trouverez des zones où H2 accepte une requête mais pas PostgreSQL, où le comportement diffère, etc . Vous trouverez également beaucoup d'endroits où PostgreSQL supporte faire quelque chose que H2 ne peut tout simplement pas - comme les fonctions de fenêtre, au moment de l'écriture.

si vous comprenez les limites de cette approche et que votre accès à la base de données est simple, H2 pourrait être OK. Mais dans ce cas, vous êtes probablement mieux candidat pour un ORM qui résume la base de données parce que vous n'utilisez pas ses fonctionnalités intéressantes de toute façon - et dans ce cas, vous n'avez pas à vous soucier de la compatibilité de base de données autant.

Tablespaces ne sont pas la réponse!

Do not utilisez une tablespace pour créer une base de données" en mémoire". Non seulement il n'est pas nécessaire, car il ne sera pas aider la performance de manière significative de toute façon, mais il est également un excellent moyen de perturber l'accès à tout autre dont vous pourriez vous soucier dans la même installation PostgreSQL. la documentation 9.4 contient maintenant l'avertissement suivant :

AVERTISSEMENT

bien que situé en dehors du répertoire principal de données PostgreSQL, tablespaces font partie intégrante du cluster de base de données et ne peuvent pas être traité comme une collection autonome de fichiers de données. Ils sont à la charge sur les métadonnées contenues dans l'annuaire et ne peut donc pas être attaché à un cluster de base de données différent ou sauvegardé individuellement. De même, si vous perdez un tablespace (suppression de fichier, échec de disque), etc), le cluster de base de données pourrait devenir illisible ou ne pas pouvoir démarrer. Placer une tablespace sur un système de fichiers temporaire comme un disque RAM risques la fiabilité de l'ensemble du cluster.

parce que j'ai remarqué que trop de gens faisaient ça et couraient dans les ennuis.

(si vous avez fait cela, vous pouvez mkdir le répertoire tablespace manquant pour obtenir PostgreSQL pour recommencer, puis DROP les bases de données manquantes, les tables etc. Il est préférable de ne pas le faire.)

59
répondu Craig Ringer 2017-05-23 12:03:02

il est maintenant possible d'exécuter une instance en mémoire de PostgreSQL dans vos tests JUnit via le composant PostgreSQL embarqué de L'option: https://github.com/opentable/otj-pg-embedded .

en ajoutant la dépendance à la bibliothèque otj-pg-embedded ( https://mvnrepository.com/artifact/com.opentable.components/otj-pg-embedded ) vous pouvez démarrer et arrêter votre propre instance de PostgreSQL dans vos crochets @Before et @Afer:

EmbeddedPostgres pg = EmbeddedPostgres.start();

ils offrent même une règle de JUnit pour avoir automatiquement JUnit démarrer et arrêter votre serveur de base de données PostgreSQL pour vous:

@Rule
public SingleInstancePostgresRule pg = EmbeddedPostgresRules.singleInstance();
13
répondu Rubms 2017-09-21 11:18:08

vous pouvez utiliser TestContainers pour lancer un conteneur docker PosgreSQL pour les tests: http://testcontainers.viewdocs.io/testcontainers-java/usage/database_containers /

TestContainers provide a JUnit @Rule / @ClassRule : ce mode démarre une base de données à l'intérieur d'un conteneur avant vos tests et la démolit ensuite.

exemple:

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);
    }
}
6
répondu Andrejs 2017-09-09 09:09:52

vous pouvez également utiliser les paramètres de configuration de PostgreSQL (tels que ceux détaillés dans la question et la réponse acceptée ici ) pour obtenir des performances sans nécessairement recourir à une base de données en mémoire.

2
répondu Dan 2017-05-23 12:18:17