Understanding HSQLDB's Architecture

Modes of Operation

HSQLDB supports three modes: in-memory, standalone file-based, and server-client. Each mode introduces different constraints and behavior in terms of persistence, threading, and transaction isolation.

File Locking and Storage Behavior

HSQLDB uses multiple files (e.g., .script, .log, .data, .properties) to persist state. Improper shutdown or concurrent access can corrupt these files or cause inconsistent read/write behavior.

Common Production Issues and Root Causes

1. Unexpected Data Loss

In file-based mode, failure to close the database using the SHUTDOWN command may lead to unsaved transactions. HSQLDB writes to .log and .data files asynchronously, increasing risk during abrupt JVM shutdowns.

Connection conn = DriverManager.getConnection("jdbc:hsqldb:file:/db/testdb", "SA", "");
conn.createStatement().execute("SHUTDOWN");

2. Database Lock Errors

Multiple processes accessing the same .data file can lead to 'file in use' or 'file lock' errors. HSQLDB does not support concurrent file-based connections unless using the server mode explicitly.

3. Table Not Found Exceptions

HSQLDB is case-sensitive for unquoted identifiers and stores metadata in-memory. When using Hibernate or JPA without quoting strategy, runtime errors may occur if table names are misaligned with casing conventions.

4. Long Startup Times

Large .log and .script files are replayed on startup to reconstruct the database. Without periodic CHECKPOINT or SHUTDOWN COMPACT, these files grow indefinitely, slowing startup and increasing corruption risk.

5. Concurrency Bottlenecks

In embedded mode, HSQLDB uses a single-writer model with synchronized access. High read/write contention results in degraded throughput, especially under multi-threaded test execution.

Diagnostics and Debugging

Enable JDBC Tracing

Set HSQLDB JDBC tracing to output detailed command execution and lock contention.

-Dhsqldb.applog=1 -Dhsqldb.lockfile=true

Inspect Data File Integrity

Corruption in .log or .script can be spotted via incomplete SQL statements or improper encoding. Use HSQLDB's DatabaseManagerSwing to browse and validate file state.

Confirm Shutdown Behavior

Verify logs contain "Database closed" and no pending transactions remain. Manual SHUTDOWN COMPACT provides both closure and file compaction.

Architectural Pitfalls

Overuse in Production

Despite its versatility, HSQLDB is not suited for high-concurrency production environments due to lack of multi-threaded transaction management and write-ahead logging.

Improper File Management

Teams often fail to version-control or snapshot .script/.log files in CI environments, leading to inconsistent state across test runs.

Use in Distributed Test Frameworks

Parallel test execution against the same file-based DB instance creates unpredictable failures. Each thread or suite should use an isolated DB path.

Step-by-Step Fixes

1. Always Use SHUTDOWN Command

Ensure graceful termination of HSQLDB sessions to persist data:

conn.createStatement().execute("SHUTDOWN COMPACT");

2. Periodic CHECKPOINT

Reduce .log file size and improve startup performance:

conn.createStatement().execute("CHECKPOINT DEFRAG");

3. Switch to Server Mode for Shared Access

Start HSQLDB as a server when multiple JVMs or apps require access:

java -cp hsqldb.jar org.hsqldb.server.Server --database.0 file:/db/testdb --dbname.0 testdb

4. Quote All Identifiers

Ensure Hibernate or SQL tools use quoted identifiers to preserve case sensitivity:

SELECT * FROM "MyTable";  -- Correct if created with mixed case

5. Isolate Embedded DB in Tests

Use dynamic paths for each test run to avoid shared file collisions:

jdbc:hsqldb:file:/tmp/testdb_12345;shutdown=true

Best Practices

  • Run SHUTDOWN COMPACT in all CI and post-test hooks
  • Use in-memory mode only for short-lived operations
  • Avoid file-based access in concurrent scenarios
  • Maintain snapshot backups of .script and .properties
  • Include startup log validation in integration tests

Conclusion

HSQLDB remains a valuable tool for embedded and development workflows, but its behavior under high concurrency and improper file handling can lead to data loss, corruption, or test instability. Senior developers and architects must understand its operational boundaries, enforce disciplined shutdown practices, and isolate its usage in shared environments. With proper setup, HSQLDB can continue to serve as a reliable backend for embedded Java systems and continuous integration pipelines.

FAQs

1. Why is my HSQLDB taking minutes to start?

Large .log or .script files are replayed at startup. Use CHECKPOINT and SHUTDOWN COMPACT regularly to minimize these files.

2. Can I use HSQLDB in a multi-user web application?

Not recommended. HSQLDB lacks the robust concurrency controls needed for high-throughput environments. Use PostgreSQL or MySQL for production.

3. How can I recover a corrupted HSQLDB?

Try restoring from .backup or .script files. If .log is corrupted, remove it and replay .script manually in a clean instance.

4. Is HSQLDB case-sensitive?

Yes, unless identifiers are unquoted. Mixed-case names require quoting during both creation and querying.

5. How do I run isolated HSQLDB instances in parallel tests?

Generate unique database file paths per test using UUIDs or temp directories. Avoid shared file paths across test threads.