ZeroZ DB · The zero-impedance database
Every entity in a conventional Java application exists as at least two things — the class and the table — plus a mapping layer whose entire job is to stop the two versions of one idea from drifting apart. ZeroZ DB deletes the second version.
The cost
Domain models in Java are translated via SQL or JPA/Hibernate to map onto relational tables — creating dual-schema maintenance for a single idea.
It expresses no business rule and produces no feature, and you maintain it for the life of the system. Its cost is invisible in a sprint and enormous in aggregate.
The compiler cannot check them, the IDE cannot refactor through them, and a rename in Java leaves a string in a repository that still compiles and now returns nothing.
N+1 selects, lazy-loading exceptions outside the session, and caches that exist entirely to undo the cost of a translation you did not want in the first place.
The solution
ZeroZ DB stores a Java object graph directly. A root object holds your maps and lists; those hold your entities; you navigate them with field access and query them with streams. The graph lives in the heap at heap speed and is written to disk as binary. There is no schema to declare, no mapping to configure and no query language to learn — because there is nothing between your classes and the storage.
ZeroZDb db = ZeroZDb.open(new MyRoot(), Path.of("data/mystore")); MyRoot root = db.root(); db.write(ctx -> { // serialized, atomic, durable on return root.prospects().put(id, prospect); // a plain Java mutation ctx.store(root.prospects()); }); List<Prospect> hot = db.read(() -> // concurrent, never sees torn state root.prospects().values().stream().filter(Prospect::isHot).toList());
If that looks like it is missing the database, that is the point. The write block is the transaction; the stream is the query.
02 · Guarantees
Object-graph persistence on its own is a storage engine, not a database. ZeroZ DB is what has to be added before a system of record can sit on one.
Every write runs inside a block that either commits entirely or leaves the graph as it was. Writes are serialized against one another, so a commit is never interleaved with another commit. Rollback restores the in-memory objects from before-images taken at enlistment — which is why the API asks you to enlist an object before you change it.
Plain object-graph engines return from a commit when the operating system has accepted the bytes, not when the disk has them: the data survives a process crash but not a power cut. ZeroZ DB forces the channel after every storage write by default. The weaker, faster behaviour is still available for bulk loads, but you have to ask for it.
Readers run against the live graph without blocking one another and without ever seeing a half-applied write. The read/write lock is deliberately fair rather than throughput-optimal: the alternative starves readers under sustained write load, which is a worse failure than a slightly slower writer.
Register an index on a field and it is kept current as part of the commit, not by a background job that can lag. A violated unique constraint aborts the whole write — including the counter you incremented three lines earlier.
When a field is renamed between releases, ZeroZ DB leaves it unset rather than filling it from an unrelated field that happens to share its type. Renames are declared explicitly. This is stricter than the underlying engine's default, on purpose: silently moving data between fields is a corruption that no test catches and no log records.
One JVM owns a store at a time, and that is enforced rather than documented. On a local filesystem an OS file lock does it. On a shared volume — where file locks are unreliable — a heartbeat-renewed lease with a fencing epoch does it, so a challenger takes over only after the lease has expired and the displaced owner stops serving within one heartbeat.
03 · Deployment
Application code is written once. Which mode a node runs in is a deployment decision, not an architectural one.
A client keeps a replica of the graph, refreshed the instant the owner commits rather than by polling, and snapshots swap atomically so a reader never observes a half-applied change. A local read never leaves the heap; a remote query crosses a socket. That gap is why the API distinguishes them — when a read has to be current rather than fast, run it as a query on the owner.
Under the hood
EclipseStore bypasses the object-relational mismatch entirely — no UPDATE statements, no N+1 queries. The in-memory graph is explicitly saved.
A commit persists what you enlisted, and enlisting does not cascade into objects already on disk. That is more work than an ORM's dirty checking, and it is the reason a commit never walks an object graph you did not ask it to walk.
No embedded engine, no driver, no separate process required. It is a library on your classpath, and in embedded mode it is the only thing in the path between your object and the file.
Limits
A database that does not tell you where it stops is not a database you should trust with a system of record.
Writes are serialized. Throughput is bounded by that and by fsync, not by the network. Systems whose bottleneck is concurrent write volume want a different database.
Queries are Java streams over maintained indexes. That is the design, not a missing feature — but it means no reporting tool will connect to it, and ad-hoc analytics belong somewhere else.
A store is bounded by the heap you can give it. Very large or cold datasets want a conventional database, or lazily-loaded sub-graphs.
The transaction, mode and schema APIs are the settled parts; the guide states which. Pin your version and read the changelog before upgrading.
The test suite kills a JVM mid-write and re-opens the store to prove nothing acknowledged was lost. A multi-process harness runs concurrent clients across real JVMs against invariants — balances that must sum, counters that must not skip, unique indexes that must hold — then re-opens and checks them again. It is published on Maven Central and it is in use in a real application. It is a young project and it does not claim otherwise.
The guide, the API, and the limitations.
Maven
<dependency> <groupId>com.zeroz4j</groupId> <artifactId>zerozdb</artifactId> </dependency>