Quarkus H2 in-mem DB - how to connect while running in quarkus:dev mode
Hello.
I am building my first Quarkus application. I want to use an in-mem DB for dev profile and use a remote one for test profile.
The dev in-mem DB is being being created on launching Quarkus and the import.sql script to fill the DB with some data seems to be picked up.
At least, the REST endpoints I wrote return the correct results.
What I would like now is to connect to the Quarkus dev in-mem DB and be able to submit SQL statements via the IntelliJ “Database” window/view.
Here my application.properties file (excerpt):
%dev.quarkus.datasource.db-kind = h2
%dev.quarkus.datasource.jdbc.url = jdbc:h2:mem:default;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1
Is that possible? If so, how is it done?
I was googling a bit and found this article: https://www.jetbrains.com/help/idea/h2.html
Here it shows how to create an H2 database and connect to it. I follow the instructions but the DB is empty.
This DB however, using the same URL from my application.properties file, can be accessed the whole time, that is, even if my Quarkus app is not running. It looks like some kind of *standalone* in-mem DB connection, which never fails the “Test connection” test.
How is it done?
Thanks
Please sign in to leave a comment.
Hi Kawu, thank you for your question!
There is a public issue about this problem with connection to in-memory DB: https://youtrack.jetbrains.com/issue/DBE-23149
You are welcome to subscribe to the issue to get updates on its progress. See this article https://intellij-support.jetbrains.com/hc/en-us/articles/207241135 if you are not familiar with our bug tracking system.
As a temporary workaround, please use a local database or a remote database instead of an in-memory DB and add it as a data source in the Database tool window.
Thanks!
I was able to hook a TCP server around the H2 in-mem DB on port 9092 programmatically like:
```
import java.sql.SQLException;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;
import org.h2.tools.Server;
@ApplicationScoped
public class ApplicationLifecycle {
Server server;
void onStart(@Observes StartupEvent event) throws SQLException {
server = Server.createTcpServer("-tcpPort", "9092", "-tcpAllowOthers").start();
}
void onStop(@Observes ShutdownEvent event) {
server.stop();
}
}
```
This code was recklessly stolen from https://stackoverflow.com/questions/57802845/quarkus-jpa-with-h2-database
Is this possible in plain Quarkus (properties files)?
Kawu, Thank you for your update.
What you’re doing here is starting an H2 TCP server (
org.h2.tools.Server) inside the Quarkus process during the application lifecycle. That’s H2-specific runtime logic, not a Quarkus feature that can be enabled purely through Quarkus datasource properties.But you can use Quarkus Dev Services for databases (for example, with PostgreSQL because H2 is not supported as a container in Dev Services). In this case, you will be able to fully configure the database without using an additional class with logic as in your example.
To use this scenario, you need:
Add the following dependency in your pom.xml (or similar if you use Gralde):
In
application.propertiesfile specify database configuration e.g.:db-kindanddevservices.*settings, and you should NOT set%dev.quarkus.datasource.jdbc.url,%dev.quarkus.datasource.usernameand etc. otherwise Dev Services will be disabled for that profile because Quarkus treats the datasource as explicitly configured.application.properties.Please let me know if you have any questions or difficulties.
Thanks for the tip/s.
The “You must have Docker installed” part was a bigger extra step than expected, which had to be taken (with some problems). I really had to make BIOS changes to activate CPU virtualization, only then Docker could actually be launched.
Dev services seem to be running now, however I still have trouble with duplicate tables. I want to run a PostgreSQL SQL (DDL) script to create the tables instead of letting Hibernate do so from the entities. The entities do not contain any annotations to reflect the `String` (VARCHAR) length of the column nor the correct types etc. for other columns.
I thought to suppress Hibernate from creating the tables via `%dev.quarkus.hibernate-orm.schema-management.strategy = none`, but sth. is not working.
Let me check…
Thanks for your update.
Since Quarkus 3.23 you should use the
quarkus.hibernate-orm.schema-management.strategyinstead ofquarkus.hibernate-orm.database.generation(https://quarkus.io/guides/hibernate-orm)So in your case you can use:
%dev.quarkus.hibernate-orm.schema-management.strategy=none%test.quarkus.hibernate-orm.schema-management.strategy=noneAnd make sure that you have no properties like:
%dev.quarkus.hibernate-orm.database.generation=drop-and-createUse
%dev.quarkus.datasource.devservices.init-script-path=db/init-dev.sqlproperty to run db init script on Dev services startup.If you still experience difficulties, please provide more us screenshot of the issue (e.g. Database tool window where we can see duplicate tables) and your
application.propertiesfile.Upload them securely to our server https://uploads.jetbrains.com/ and provide us with the Upload ID.
The property:
%dev.quarkus.hibernate-orm.schema-management.strategy=none
seems to do the job now. Thanks so much!
PostgreSQL Docker is up an running in dev mode/profile with the following init scripts being picked up (I created a subdir “db” in the src/main/resources dir):
%dev.quarkus.datasource.devservices.init-script-path=db/create-tables-postgresql.sql, db/insert-data-postgresql.sql
I can see the correct data from the DS connection, manipulate data etc.
Two problems remain however:
1. The schema name is always “public”
From the create-tables-postgresql.sql:
Prefixing the table names with a schema name like:
leads to
Caused by: org.postgresql.util.PSQLException: ERROR: schema "retract" does not existPosition: 28How do you launch a dev PG container giving “it” a specific schema name other than “public”?
See IJ connection:
2. At startup, Hibernate complains with “
Failed to validate Schema”:Maybe you have a link/solution…?
Thanks
1. You should create a new schema and then add the tables to it. For example, add creating a new schema to
db/create-tables-postgresql.sqland then create a new table in that schema:2. The error you see is coming from schema validation. By default, Quarkus/Hibernate ORM performs a post-startup validation of the database schema in dev mode and logs any mismatches. This behavior is controlled by:
quarkus.hibernate-orm.validate-in-dev-mode(default: true). See this doc.From your screenshot, it looks like the code column is defined as a fixed-length type in PostgreSQL (CHAR(2) / bpchar). In this case you have two options:
The first option (recommended):
Align the entity mapping with your DDL by explicitly specifying the column length, e.g.:
The second option:
Disable dev schema validation if you don’t want to keep entities strictly aligned with the DDL:
%dev.quarkus.hibernate-orm.validate-in-dev-mode=falseHmm. Prefixing table names with their schema name is not good. One of my big tasks is to create DB scripts that can replicate the DB on any PG system. The remote development schema name is “retract.e”, so I will live with the default schema name “public” for dev setup.
As for the 2nd I set the property to false for now until I might add the meta info per column later.
Thanks so much for helping! Invaluable info.
Thanks for the update.
I understand that it may be not the best solution for all cases. In your case, the
SET search_pathcommand might be useful, for example:In this case, table creation/search will be performed in the retract schema, and if it is not found, then in public.
This will allow you to avoid changing the script in multiple places when switching the prefix to another one, and instead define the schema only once in your initialization script.
Please feel free to correct me if I did not fully understand your scenario correctly.