Concept :
- Vous avez une base H2 sur le réseau.
- Vous en avez setupé une autre ailleurs sur le réseau.
- Toutes les actions en écriture effectuées sur la première seront répliquées sur les autres. Ca nous fait donc des backups à pas cher.
Comment faire ?
- On démarre les instances A et B
# Instance A
java org.h2.tools.Server
-tcp -tcpPort 9101
-baseDir instance-A
# Instance B
java org.h2.tools.Server
-tcp -tcpPort 9102
-baseDir instance-B
Puis on démarre une troisième instance qui sera le cluster des deux autres :
# Cluster
java org.h2.tools.CreateCluster
-urlSource jdbc:h2:tcp://localhost:9101/~/test
-urlTarget jdbc:h2:tcp://localhost:9102/~/test
-user sa
-serverList localhost:9101,localhost:9102
Notre application se contentera de se connecter au cluster qui fera la réplication lui-même.
Nota Bene
- Ce système ne marche pas avec une base embarquée !
- Ce système effectue toujours les requêtes sur le premier nœud, le second n'est là que comme backup.
Et en cas de plantage ?
Simple, il suffit de :
- Se rendre sur le nœud qui est tombé.
- Dropper les datafiles.
- Relancer l'instance.
- Relancer le cluster (qui se chargera de répliquer tout sur l'instance remise à zéro).
Cette procédure de restauration peut prendre du temps sur les grosses bases mais je vois mal un SI de plusieurs tera-octets sur H2DB de toutes façons. Par contre, et au vu de la simplicité de configuration/installation de H2, ça peut être bien pour des BDD de moins de 32 Go
Pourquoi 32 Go et pas plus ?
Car avec une vitesse de réplication de 10 Mo / sec, ce qui est assez fréquent sur des petits VPS, la réplication des 32 Go prendra moins d'une heure, ce qui reste acceptable. Quant aux petites bases de moins de 1 Go, en 1 ou 2 minutes tout sera plié.
Pour peu qu'on ait mis en place un monitoring des instances et un rôle Ansible capable de restaurer les nœud déclenché par un hook, alors la procédure peut se faire automatiquement et sans effort, et j'aime le DevOps facile :D
La base H2DB intègre un moteur NoSQL au format clef-valeur.
Elle gère les accès concurrents en lecture/écriture et les connexions effectuées en parallèle par de multiples utilisateurs.
La documentation de la base indique que le mode concurrent est toujours qualifié de beta, mais il existe depuis la 1.3.x en expérimentale, et en "to qualify" depuis la 1.4.x.
C'est le cas depuis 2010 donc... Je pense qu'en 8 années et 196 patch (de la 1.4.0 à 1.4.196) on devrait être bons là nan ?
Bref, si H2 intègre un mode "dump before update" ou que je parvienne à en faire un, je switch et j'abandonne PostgreSQl et MySQL à son profit.
Un résumé expliquant comment utiliser facilement H2BD (création d'une connexion, ajout de la base en dépendance Maven, création d'un pool de connexion, connectivité avec Hibernate & JPA, URL à utiliser, etc.
Voici quelques exemples :
Cas pour rendre les données persistantes sur le disque :
# Pour stocker les données de la base dans le répertoire TEST de votre home
jdbc:h2:~/TEST
# Pour stocker les données de la base dans le répertoire /data/TEST
jdbc:h2:/data/TEST
URL pour l'écriture en mémoire (données non persistantes) :
# Permet d'avoir plusieurs connexion pour une même instance (processus) :
jdbc:h2:mem:test
# Permet de n'avoir qu'une seule connexion (schéma anonyme et privé) :
jdbc:h2:mem:
Changer le dialect SQL de H2DB pour employer celui d'une autre base :
La liste des modes de compatibilité est disponible ici
# Pour Apache Derby
jdbc:h2:mem:MON_SCHEMA;MODE=Derby
# Pour DB2
jdbc:h2:mem:MON_SCHEMA;MODE=DB2
# Pour MySQL
jdbc:h2:mem:MON_SCHEMA;MODE=MySQL;IGNORECASE=TRUE
# Pour Oracle
jdbc:h2:mem:MON_SCHEMA;MODE=Oracle
# Pour PostgreSQL
jdbc:h2:mem:MON_SCHEMA;MODE=PostgreSQL
Exécution de scripts SQL au démarrage de la base :
# Pour exécuter un script SQL au démarrage de l'instance de la base :
jdbc:h2:mem:test;INIT=create schema if not exists test\;runscript from '~/sql/init.sql'
Et comment utiliser cette base dans un fichier :
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class driver = Class.forName("org.h2.Driver");
Connection connect = DriverManager.getConnection("jdbc:h2:file:/mon/repertoire/ou/stocker/mes/donnees", "my_user_name", "my_password");
connect.close();
}