I have a requirement where I need to grab the Insert and Update Native SQL statement being fired and store it in a log table in the DB. Is it possible for me to get the query in eclipselink?
Register your own custom logger that logs to your database rather than to the file system and configure eclipselink.logging.level.sql=FINE in the persistence unit. Then you can piggy-back on the existing solution for logging SQL statements and save them to the log table. See http://wiki.eclipse.org/EclipseLink/Examples/JPA/CustomLogger and https://wiki.eclipse.org/EclipseLink/Examples/JPA/Logging for details.
Related
I'm building a SpringBoot application with spring-data-jpa. I know how to log all sqls from this question. How to print a query string with parameter values when using Hibernate
But what if I only want to log failed sqls?
There are two options:
Configure sql logging with parameter values. Disable jdbc batching and enable flushing through hibernate means.
Add debug JDBC driver such as p6spy that will more or less do exactly as described above.
First, let's analyze the problem and split the query types into SELECT and INSERT/UPDATE queries.
SELECT queries for them you have the flushing on by default. So when an error occurs you know exactly which query has failed.
INSERT/UPDATE queries, here things get tricky because your flushing will be off and you have query batching which means that first when you run the query it gets delayed. Second, it gets packed up with other unrelated queries, and third, Hibernate may re-order them. So the short answer is that this is not doable for INSERT/UPDATE if you are using hibernate alone.
A solution to your problem needs to do essentially two things:
1. It should log the queries with their parameter values. This can be done the following way:
# logs the SQL statements
log4j.logger.org.hibernate.SQL=debug
# Logs the JDBC parameters passed to a query
log4j.logger.org.hibernate.type=trace
2. The solution needs to disable the batching of queries, otherwise, you will get a bunch of SQLs but you will not know which SQL exactly is the problematic one.
hibernate.jdbc.batch_size=1
Not sure if this will be enough to entirely disable the batching, but you need to find out.
Alternatively, you can use a jdbc driver designed for DEBUG. This would be p6spy driver which has the option to flush every single SQL statement which is exactly what you want.
Here you need to set the autoflush=true configuration parameter to ensure every single sql statement is immediately flushed to the database.
https://p6spy.readthedocs.io/en/latest/configandusage.html
This gives you multiple log entries. In my case this was not welcome.
Here is my solution for it:
dependency net.ttddyy:datasource-proxy:1.6
Wrap Datasource in Spring Configuration
#Bean
public DataSource dataSource() {
return ProxyDataSourceBuilder.create(originalDatasource())
.logQueryBySlf4j(FLF4JLogLevel.DEBUG).build();
}
Write your own LogAppender - here you can filter the logevents, so you can filter i.e for inserts only or failed executions
public class SQLAppender extends AppenderBase
[...]
#Override
protected void append(ILoggingEvent eventObject) {
[...]
}
configure logback.xml
<appender name="mySQLAppender" class="com.my.SQLAppender" >
</appender>
<logger name="net.ttddyy.dsproxy.listener.logging.SLF4JQueryLoggingListener" level="DEBUG"\>
<appender-ref ref="mySQLAppender"/>
</logger>
We are developing the ADF application, where in we came accross the requirement that we have to log all the operations into the database which user has performed like all the DML operations (Insert, update , delete), this can be achieved by overriding the doDML method of entity impl class, but now one more requirement is there where we have to log the event when user has queried the records i.e DQL.
May I Know which entity impl method is getting called when we queries the record?
or is there any other way to perform audit logging when user queries the record in ADF?
Thanks
You can use this method to intercept querying:
protected void bindParametersForCollection(QueryCollection qc,
java.lang.Object[] params,
java.sql.PreparedStatement stmt)
throws java.sql.SQLException
Please check slide 10, but use this method instead of executeQueryForCollection() if you run JDev 12c
I'm looking for way to get the SQL update script when Hibernate automatically updates tables.
I'm using hibernate.hbm2ddl.auto=update in development environment only, and I need SQL script that updates tables for production.
I want these SQL scripts in txt format for revision and potential edit.
How can this be done?
Thanks for any advice.
There are some suggestions and general discussion here.
In a nutshell, you can turn on logging (to standard output):
hibernate.show_sql=true
Alternatively, if you use log4j, you can add this to your log4j.properties file:
log4j.logger.org.hibernate.SQL=DEBUG
Both of these approaches are going to output Hibernate's prepared statements with parameters (so the parameter values themselves are not inline). To get around this, you could use an interceptor like P6Spy. Details on that can be found here.
org.hibernate.cfg.Configuration class has method:
public java.lang.String[] generateSchemaUpdateScript( Dialect, DatabaseMetadata)
what generates the reqiured update script.
I've just implemented this in grails:
configuration = new DefaultGrailsDomainConfiguration(
grailsApplication: grailsApplication,
properties: props)
//this extends hibernate config
Connection c = SessionFactoryUtils.getDataSource(sessionFactory).getConnection(props.'hibernate.connection.username', props.'hibernate.connection.password')
<br/>md = new DatabaseMetadata(c, DialectFactory.buildDialect(props.'hibernate.dialect'))
configuration.generateSchemaUpdateScript(DialectFactory.buildDialect(props.'hibernate.dialect'), md)
)
check SchemaExport script in grails, for further information, it uses hibernate to generate schema.
(I had to implent is as a service because we have external domain model)
I need to be able to set a MySQL user variable that is used in a trigger in a Spring MVC Hibernate web ap. This user variable is used in MySQL triggers on the tables that are being manipulated by Hibernate. I need this user variable to be correctly set during all of Hibernate's write accesses to the database.
Unfortunately HQL does not have a technique for setting MySQL user variables and the method I have found for directly executing MySQL does not seem to work with the transaction. Since the user variable's life span is that of the database connection I need the MySQL to execute using the same connection that they HQL will be executed with. However my transactions seem to run the HQL after the native MySQL has been executed and thus the expected user variable is not present for the MySQL trigger.
To execute native MySQL queries I have been using:
HibernateEntityManager em=(HibernateEntityManager) getEntityManager();
Connection connection=em.getSession().connection();
Statement s = connection.createStatement();
s.executeUpdate("SET #current_user_id="+userId);
When the Spring MVC commits my transaction it runs the HQL queries and then throws an exception because the #current_user_id is causing the MySQL trigger to break. I verified this by testing without the triggers present.
I found this SO question that is very similar to mine: How to use Mysql variables with Hibernate?
So I followed the suggestion and used a stored procedure and the executeNativeQuery method on the entity manager to call it.
Here is my stored procedure code:
DROP PROCEDURE IF EXISTS set_current_user
CREATE PROCEDURE set_current_user(IN user_id BIGINT)
BEGIN
SET #current_user_id = user_id
END
And I call it with:
Query q = em.createNativeQuery("CALL set_current_user("+userId+")");
q.executeUpdate();
I have a Spring/Hibernate webapp that has some integration tests that run on an in-memory HSQL database. Hibernate takes this blank database and creates all of my test tables and constraints thanks to hbm2ddl=create. However, I have a new bean that checks for a particular config value from the database during its afterPropertiesSet() method, and so when this bean is initialized, such a row needs to exist in the database.
Is there any good way to set up a Java/Spring/Hibernate equivalent of Rail's test fixtures? I'm trying to find a way to tell Hibernate "whenever you create this table, insert these rows immediately afterwards". I couldn't find a callback or a hook I could add, but maybe there's another way.
I'm trying to find a way to tell Hibernate "whenever you create this table, insert these rows immediately afterwards"
Since Hibernate 3.1, you can include a file called import.sql in the runtime classpath of Hibernate and at the time of schema export, Hibernate will execute the SQL statements contained in that file after the schema has been exported.
This feature has been announced in the Rotterdam JBug and Hibernate's import.sql blog post:
import.sql: easily import data in your unit tests
Hibernate has a neat little feature
that is heavily under-documented and
unknown. You can execute an SQL script
during the SessionFactory creation
right after the database schema
generation to import data in a fresh
database. You just need to add a file
named import.sql in your classpath
root and set either create or
create-drop as your
hibernate.hbm2ddl.auto property.
I use it for Hibernate Search in
Action now that I have started the
query chapter. It initializes my
database with a fresh set of data for
my unit tests. JBoss Seam also uses it
a lot in the various examples.
import.sql is a very simple feature
but is quite useful at time. Remember
that the SQL might be dependent on
your database (ah portability!).
#import.sql file
delete from PRODUCTS
insert into PRODUCTS (PROD_ID, ASIN, TITLE, PRICE, IMAGE_URL, DESCRIPTION) values ('1', '630522577X', 'My Fair Lady', 19.98, '630522577X.jpg', 'My Fair blah blah...');
insert into PRODUCTS (PROD_ID, ASIN, TITLE, PRICE, IMAGE_URL, DESCRIPTION) values ('2', 'B00003CXCD', 'Roman Holiday ', 12.98, 'B00003CXCD.jpg', 'We could argue that blah blah');
For more information about this
feature, check Eyal's blog, he
wrote a nice little entry about it.
Remember if you want to add additional
database objects (indexes, tables and
so on), you can also use the auxiliary
database objects feature.
It is still not really documented.
In hibernate 3.6 the configuration that allows to run arbitrary sql commands is:
hibernate.hbm2ddl.import_files
See in http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/, noticing there is an error in the documentation: the property is import_files, with an s in the end.
If you're talking about JUnit tests and using AbstractTransactionalDataSourceSpringContextTests there's methods you can override like onSetupBeforeTransaction that provide a hook to pre-populate test table data etc.