Die neue in Memory Datenbank
Microstream ist die neue in Memory Datenbank für Java. Aus dem Hause XDev stammt diese revolutionäre Datenbank. Nachdem im Frühjahr das Produkt umbenannt worden ist, heißt es nicht mehr JetstreamDB sondern Microstream. Die Microstream Datenbank ist kostenlos und kann frei verwendet werden.
Was ist Microstream?
Microstream ist ein Framework das Java Objekte ultraschnell serialisieren und desialisieren des kann. Das macht sich Microstream zu nutze und umgeht damit unvermeidbare Netzwerklatenzen, die ansonsten bei klassischen RDBMs entstehen.
Wie funktioniert Microstream?
Es gibt eine Root Entität. Diese enthält alles was in der Datenbank gespeichert werden soll. Es gibt also hier kein Datenbank Schema oder ähnliches. Die Java Objekte sind die Entitäten. Das war es. Alles was sich also in dem Objektgraph unterhalb der Root Entität befindet, kann persistiert werden.
Was ist mit Queries?
Abfragen, wie man es bei einer normalen RDBMs kennt, gibt es nicht. Und braucht man auch nicht. Man verwendet einfach das Streaming API von Java und erreicht Wahnsinnig schnelle Abfragen in Millisekunden Bereich.
Demoanwendung
Es soll hier in einer kleinen Demoanwendung die Verwendung der Microstream API veranschaulicht werden. Ich verwende hier das SpringBoot Framework in der aktuellsten Version 2.1.4. Die Anwendung erzeugt bei jedem Start eine neue Einladung. Die Einladungen bestehen aus einer ID und einem Namen. Super einfach. Die ID wird hierbei immer um einen erhöht. Der Name ist hier statisch. Um den Code vom unnötigen Boilerplate frei zu halten, verwende ich Lombok.
Abhängigkeiten einbinden
Es muss das Repository von microstream eingebunden werden. Die Group ID .heißt one.microstream und es muss das Artefakt storage.embedded in der Version 01.00.00-MS-RC1 Hier das Gradle Buildscript:
repositories {
mavenCentral()
maven { url 'https://repo.microstream.one/repository/maven-releases/' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation('one.microstream:storage.embedded:01.00.00-MS-RC1')
annotationProcessor('org.projectlombok:lombok')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Die Entität
Die Invocartion stellt die Entität des Repositories dar. Sie besteht aus der ID und dem Namen der Einladung.
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Invocation {
private Long id;
private String name;
}
Pretty simple, aber erfüllt für die Demo genau seinen zweck.
Insert new Invocation
Der CommandLineRunner wird beim Starten des SpringBoot Container ausgeführt. Es sind für die Verwendung der in Memory Datenbank zwei statische Variable nötig. Die eine enthält das Root des Objektgraphen hier ROOT genannt und eine STORAGE die für das Persistieren auf der Festplatte.
Wie gelange jetzt die Daten in den Objektgraphen?
@Component
@Log
public class InitDatabase implements CommandLineRunner {
// to stop spring boot application
@Autowired
private ConfigurableApplicationContext cac;
// this is the ROOT of object graph
private static Reference<InvocationRepository>ROOT =
X.Reference(new InvocationRepository());
// Storage manager
private static EmbeddedStorageManager STORAGE =
EmbeddedStorage.start(ROOT);
@Override
public void run(String... args) throws Exception {
// load all into a local list
var rootData = ROOT.get();
List<Invocation> invocations = rootData.getInvocations();
// print size of Repository
log.info("size: " + rootData.size());
// add a new Incocation to Repository
Invocation invocation = new Invocation();
invocation.setId(Long.valueOf(rootData.size()+1));
invocation.setName("Test");
invocations.add(invocation);
invocations.forEach(i-> log.info(i.toString()));
// store
STORAGE.store(ROOT.get().getInvocations());
// close
STORAGE.shutdown();
// shutdown SpringBoot container
cac.close();
}
}
Das Repository
Das Repository ist sehr einfach gehalten.
public class InvocationRepository {
private final List<Invocation> invocations = new ArrayList<>();
/**
* get a List of Invocations
* @return List of Invocation
*/
public List<Invocation> getInvocations() {
return invocations;
}
/**
* Size of Repository
* @return
*/
public int size() {
return invocations.size();
}
}
Einschränkungen
Leider gibt es mit dem Classloader ein Problem, wenn man die DevTools von SpringBoot mit einbindet. Daher habe ich diese aktuell noch nicht eingebunden.