How to check long-runing queries in spring boot/postgresql application? - spring

I have a Spring boot application with Hibernate, connecting to a PostgreSQL database. After some time, some users experience a problem with slow requests or requests without any response.
I suspect some long-running SQL queries, but how can I check which queries run long? I would like to log down execution times of queries. I know show-sql parameter for Hibernate, but it doesn't display arguments for SQL statements, nor it doesn't log execution times. Is there any other way to achieve that?

You can log slow queries in hibernate by setting the property:
spring.jpa.properties.hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS=100
Also, if you want to log SQL statements with parameters, you can use:
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

Related

Log effective URL for Spring Boot Liquibase

I'm using Spring Boot 2.7. When I run a unit test, it insists on creating the Liquibase change log table either twice for what should be an H2 in memory database. I'd like to have Liquibase log the actual JDBC URL being used. I know what the properties say, but I have an application.properties, an application-h2.properties, and sometimes Spring wants to use an in memory database even though a different in memory database is used.
Is there some property like
spring.liquibase.show-effective-jdbc-url=true?
Bonus points for telling me how to log this for regular JPA access.
Thanks,
Woodsman
There is not a flag, but the effective URL is logged at FINE level. There should be a message like Connected to USER#URL where the value for url is returned from the driver itself, not just what you gave it.

How to insert/update native queries in DB using spring JPA?

Am working on a Spring boot application using spring data JPA. The DB is a legacy one. There is a staging table which contains insert/update queries as CLOB data.
I have written a pojo for the staging table. The pojo implements CRUDRepository interface. I fetched the records from list() method and iterate the CLOB data. The queries present in the CLOB needs to be executed in other DB. The queries are insert/update queries related to 20+ tables.
Without creating pojos for that 20+ tables, how can I execute those SQL's.
The SQL's need no modifications, just need to execute the same that I fetch from the staging table. Is
EntityManager.createNativeQuery("insert/update")
a possible solution, or is there a better approach to handle it.
You could do that with JPA native queries for sure. Or even with plain JDBC.
But I recommend having a look at jOOQ. jOOQ generates POJOs for accessing and modifying the data and has a DSL that leads to compile time checked data access:
https://www.jooq.org/
jOOQ is free for OpenSource databases like MySQL, PostgreSQL etc. and affordable for commercial ones like Oracle.

Table not found after apparently successful migration

I was using flyway through the CL to migrate my production DB (mySql), while I was using a fixed SQL query to create the DB, tables, etc. in my unit tests, using H2. I'd like now to better integrate flyway and create/delete DB after each unit test.
I have a DB factory and inside its build method I'm using the following code:
flyway.setLocations("filesystem:sql/migrations/common","filesystem:sql/migrations/h2");
flyway.setSchemas("MYSERVER");
flyway.setDataSource(
p.getProperty(DB_URL.getName()),
p.getProperty(USERNAME.getName()),
p.getProperty(PASSWORD.getName()));
flyway.setInitOnMigrate(true);
flyway.migrate();
The migrations seems to apply correctly, as I can see my SQL code from the flyway logs. But when I start using the DB, immediately afterwards, I get TABLE NOT FOUND errors. I'm using h2 as in memory DB with the following URL to initialize my client:
jdbc:h2:mem:MYSERVER;MVCC=true
Do you have any idea on what I might be making wrong?
The problem is your JDBC url.
MYSERVER is the name of the database, not the schema.
The easiest thing to do is to let flyway use the same url, and not set a schema. This way you'll find everything in the public schema of the MYSERVER database.
Having the same issue - after digging around, it appears that the H2 database is being recreated between migration scripts somehow.
You can confirm this happens by putting a SELECT * FROM migrations in the first two migrations - it will succeed in the first and fail in the second.
According to the H2 Documentation, specifying a database name and ;DB_CLOSE_DELAY=-1 option should suffice to allow concurrent and subsequent accesses to the in-memory database, however this is not the case.
Upgrading Flyway from 3.1 to 3.2.1 has fixed the problem.

Hibernate/JPA vs JDBC performance

We are using JPA/Hibernate for project where we need to insert, say 10000 records in database with multiple joins/relations etc. The functionality is fine but the performance is really slow.
Just wondering if migrating to JDBC will help in some performance gain?
Thanks,
-csn
You can do batch inserts with JPA/Hibernate - see "Batch processing".
You would almost certainly get better performance by doing batch inserts in JDBC (addBatch(), etc), but the Hibernate method may be more desirable if your schema is complex.
If you use JDBC batches, make sure that you do all of your addBatch() calls in a transaction.
If you happen to be using MySQL, be sure to add rewriteBatchedStatements=true to your connection parameters.

GORM (Hibernate) Interceptor to run certain SQL before Hibernate runs it in the db in a Grails application?

I have a grails application in which I am using GORM. This works great. However I have a requirement where, before any SQL is called in the database, it has to run a certain stored procedure. So, is there a way I can do something that will trigger my method that kicks off a stored procedure before Hibernate runs the SQL for select, insert, update, delete etc.
Your response will be greatly appreciated.
(P.S.- The reason I have to run certain stored procedure is to change Oracle Workspace)
There might be several options.
You could use a dataSource wrapper that extends org.springframework.jdbc.datasource.DelegatingDataSource and runs the statement whenever getConnection is called.
I guess it's ok to call the statement (stored proc) only once per transaction, so DelegatingDataSource is probably the most approriate solution.
You could also use http://www.grails.org/plugin/jdbc-pool plugin (wraps Tomcat JDBC Pool) and try to hook to the datasource pool implementation. Tomcat JDBC Pool supports interceptors.
It's also possible to modify the SQL sent by GORM/Hibernate using a Hibernate interceptor, if that helps: Is it possible to map a table name for a domain object dynamically in grails? .
It's not clear whether you want to run this stored proc once before any SQL is executed, or before every SQL statement is executed. Here's a suggestion for both cases:
Once Only
Call the method that invokes the stored proc in Bootrap.init()
Before Every
Call the method from the before* GORM event handlers

Resources