| name | h2 |
| description | Expert in H2 embedded database - in-memory and file-based SQL database for Java applications. Use this when configuring H2 database, writing JDBC code, or setting up test databases. |
| license | MIT |
H2 Database Expert
Expert in H2, the lightweight embedded Java SQL database engine for development, testing, and lightweight production use.
When to Use This Skill
- Setting up H2 database for Java applications
- Configuring JDBC connections
- Writing SQL for H2
- Integrating H2 with Python (via jaydebeapi)
- Setting up test databases
- Running H2 console
H2 Database Basics
Key Features
- Embedded: Runs in same JVM as application
- In-memory: Fast, lost on shutdown
- File-based: Persistent storage
- Server mode: Multiple connections
- Small footprint: ~2.5MB JAR file
- SQL compatibility: MySQL, PostgreSQL modes
JDBC URL Patterns
jdbc:h2:mem:testdb
jdbc:h2:mem:mydb
jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
jdbc:h2:file:./db/mydb
jdbc:h2:file:/absolute/path/to/db
jdbc:h2:file:./db/mydb;AUTO_SERVER=TRUE
jdbc:h2:mem:testdb;MODE=MySQL
jdbc:h2:mem:testdb;MODE=PostgreSQL
Java Integration
Maven Dependency
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version>
<scope>test</scope>
</dependency>
Basic JDBC Connection
import java.sql.*;
public class H2Example {
public static void main(String[] args) throws Exception {
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection(
"jdbc:h2:mem:testdb",
"sa",
""
);
Statement stmt = conn.createStatement();
stmt.execute("CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(100))");
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO users VALUES (?, ?)"
);
pstmt.setInt(1, 1);
pstmt.setString(2, "John Doe");
pstmt.executeUpdate();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
while (rs.next()) {
System.out.println(rs.getInt("id") + ": " + rs.getString("name"));
}
rs.close();
stmt.close();
pstmt.close();
conn.close();
}
}
Python Integration
Using jaydebeapi
import jaydebeapi
conn = jaydebeapi.connect(
"org.h2.Driver",
"jdbc:h2:./db/database",
["sa", ""],
"/path/to/h2.jar"
)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
)
""")
cursor.execute("INSERT INTO users VALUES (?, ?, ?)", (1, 'John', 'john@example.com'))
conn.commit()
cursor.execute("SELECT * FROM users")
for row in cursor.fetchall():
print(row)
cursor.close()
conn.close()
Installing Dependencies
poetry add jaydebeapi jpype1
pip install jaydebeapi jpype1
H2 Console (Web UI)
Starting the Console
java -cp h2.jar org.h2.tools.Console
java -cp h2.jar org.h2.tools.Console -web -webPort 8082
Console Connection
- JDBC URL:
jdbc:h2:./db/mydb
- User:
sa
- Password: (empty by default)
Common SQL Operations
Table Creation
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_email ON users(email);
CRUD Operations
INSERT INTO users (name, email) VALUES ('John', 'john@example.com');
SELECT * FROM users WHERE email LIKE '%@example.com';
UPDATE users SET name = 'Jane' WHERE id = 1;
DELETE FROM users WHERE id = 1;
Useful Functions
CREATE TABLE items (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
);
SELECT CURRENT_TIMESTAMP;
SELECT CONCAT(first_name, ' ', last_name) FROM users;
SELECT UPPER(name) FROM users;
SELECT SUBSTRING(name, 1, 3) FROM users;
Database Modes
MySQL Compatibility
jdbc:h2:mem:testdb;MODE=MySQL;DATABASE_TO_LOWER=TRUE
Features:
- MySQL-style string concatenation
- LIMIT clause
- MySQL date functions
PostgreSQL Compatibility
jdbc:h2:mem:testdb;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE
Features:
- PostgreSQL-style string functions
- LIMIT/OFFSET
- PostgreSQL data types
Configuration Options
Common Options
jdbc:h2:file:./db/mydb;AUTO_SERVER=TRUE
jdbc:h2:mem:testdb;CASE_INSENSITIVE_IDENTIFIERS=TRUE
jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=2
jdbc:h2:file:./db/secure;CIPHER=AES
Testing with H2
JUnit Test Example
@BeforeEach
void setUp() throws SQLException {
connection = DriverManager.getConnection(
"jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1",
"sa",
""
);
Statement stmt = connection.createStatement();
stmt.execute("CREATE TABLE IF NOT EXISTS users (id INT, name VARCHAR)");
stmt.close();
}
@AfterEach
void tearDown() throws SQLException {
if (connection != null) {
connection.close();
}
}
@Test
void testInsertUser() throws SQLException {
PreparedStatement pstmt = connection.prepareStatement(
"INSERT INTO users VALUES (?, ?)"
);
pstmt.setInt(1, 1);
pstmt.setString(2, "Test User");
int rows = pstmt.executeUpdate();
assertEquals(1, rows);
}
Troubleshooting
Common Issues
Database locked:
- Close all connections properly
- Use AUTO_SERVER mode for file databases
- Check if another process is using the database
File not found:
- Use absolute paths or
./relative/path
- Ensure directory exists
- Check file permissions
Out of memory:
- Use file-based database instead of in-memory
- Limit query result size
- Increase JVM heap size
Best Practices
- Use in-memory for tests - Fast and clean
- Close connections - Always close in finally/try-with-resources
- Use prepared statements - Prevent SQL injection
- Enable AUTO_SERVER for file DBs with multiple connections
- Set DB_CLOSE_DELAY=-1 for test databases
- Choose appropriate mode - MySQL/PostgreSQL compatibility if needed
Project Context
In this project:
- H2 JAR located at:
db/h2.jar
- Currently using SQLite instead of H2
- H2 available for future migration if needed
- Can integrate with Python Flask API via jaydebeapi
Migration Example (SQLite to H2)
DB_PATH = 'db/thoughtful_ai.db'
conn = sqlite3.connect(DB_PATH)
import jaydebeapi
conn = jaydebeapi.connect(
"org.h2.Driver",
"jdbc:h2:./db/thoughtful_ai;DB_CLOSE_DELAY=-1",
["sa", ""],
"./db/h2.jar"
)