I am running a complex query via the Hibernate Criteria API. During debug, I would like to be able to extract and log the parameters that have been bound to the criteria object. Using Hibernate's org.Hibernate.type logger is not an option because during the server start there are many many queries that are run and the logger causes a serious performance hit, and as we are using Hibernate 3.5, it cannot be configured to be turned on before and after the specific method call, only when the server starts.
As far as getting the SQL query itself, in this answer someone posted excellent code that allows for extracting the SQL from a criteria, is there a similar solution for the bound parameters?
You can log the Criteria and the Restrictions will be displayed as well:
Criteria criteria = session.createCriteria(Post.class)
.add(Restrictions.eq("title", "post"));
LOGGER.info("Criteria: {}", criteria);
will display:
Criteria: CriteriaImpl(com.vladmihalcea.book.hpjp.hibernate.association.AllAssociationTest$Post:this[][title=post])
Related
I have a sample query like the following
String hql = "from Stock s where s.stockCode = :stockCode";
List result = session.createQuery(hql)
.setParameter("stockCode", "7277")
.list();
the result is a list like I expect it to be but I want to know how I can sysout the sql query in my Tomcat logs before the query is executed. Can I do it at the code level as opposed to setting a property in log4j or hibernate config?
In this case, I am looking for an output like
select * from Stock s where s.code = 123;
To access SQL at the code level, you can use the datasource proxy library with a listener.
You can find the example of the datasource proxy and its listener at my github repo jpa-puzzles.
However, if you only want to see the sql-s with bound parameters (show-sql shows only sql-s without bound parameters), it's easier to use a hibernate configuration:
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
We are using pgPool in our Java project to do load balancing in our Postgres database.
pgPool sends read only queries to slave servers and write queries to the master. That is ok.
But there are very specific cases in our application when we need the query to be executed in master server only.
pgPool provides the following mechanism:
/*NO LOAD BALANCE*/ SELECT * FROM user;
The query above will always be executed in the master server.
I searched a lot but while it is possible to set a comment in a manual query (there is a setComment() in Query class), I couldn't find a way to do that using a Hibernate repository with queries created from method names.
Example:
public interface UserRepository extends Repository<User, Long> {
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
How to put the comment in this query?
Well, this not answers the original question, but I've solved the problem using a different approach.
I've found the solution by reading this section of pgPool documentation: http://www.pgpool.net/docs/latest/pgpool-en.html#condition_for_load_balance
So, annotating a Java method or class with #Transactional achieves the desired result of routing the queries to master server.
When using this annotation, pgPool will route all queries made after a WRITE query (including) to the Postgres master server.
If you don't have a WRITE query, you can achieve the result by annotating with #Transactional(isolation=Isolation.SERIALIZABLE) - if using Spring. But be aware that this isolation level is the strictest available.
Here is my criteria:
public Commercial findManager(Entity entity) {
DetachedCriteria criteria2 = DetachedCriteria.forClass(Role.class);
criteria2.createAlias("workStation", "workStation");
criteria2.createAlias("workStation.entity", "entity");
criteria2.add(Restrictions.eq("entity.id", entity.getId()));
criteria2.createAlias("commercial", "commercial", CriteriaSpecification.LEFT_JOIN);
criteria2.setFetchMode("commercial", FetchMode.JOIN);
criteria2.createAlias("commercial.function", "function");
criteria2.add(Restrictions.eq("function.name", "MANAGER"));
criteria2.setProjection(Projections.property("commercial"));
Commercial commercial = (Commercial) getHibernateTemplate().findByCriteria(criteria2).get(0);
return commercial;
}
This criteria works as intended except that it returns a proxy. Since I am going to query a lot of properties on that proxy I want to force hibernate to load that object in the same query, but even with fetchmode in JOIN mode it does not seem to work. What is wrong?
I use hibernate 3.3.2 and spring 2.5
Thanks to Dragan, I figured out that the proxy was actually initialized. It was actually a bad interpretation of what I was seeing in the JDBC log and in the debugger.
I was seeing this:
But when looking deeper into it, I figured out that the data was there, and making logs into the console for the data did not trigger new calls to the database:
After some more investigations I figured out that the FetchMode.JOIN and CriteriaSpecification.LEFT_JOIN in the original request are actually not needed to get this result. But the Adress field, which is a complex object, was not initialized, and querying on its attributes generated new requests to the database. Then I tried to add the following line and now it works like a charm (like in the previous screenshot where we can see that the adress field is a proxy)
criteria2.setFetchMode("commercial.adresse", FetchMode.JOIN);
I have the following code
resultList = daoResources.jdbcTemplate.query(sql, selectParams, new BeanPropertyRowMapper(resultClass));
SQL when run with the selectParams against database, I get result. The selecting fields name of the sql matches with the fields in the resultClass too. But for above code, I get an empty resultList.
Where could be the problem?
Debugging is your friend in this scenario. I suggest you enable debug logs for jdbc template to see what sql's and bind parameters are sent to database. Below is from the 3.0.x reference doc
All SQL issued by this class is logged at the DEBUG level under the
category corresponding to the fully qualified class name of the
template instance (typically JdbcTemplate, but it may be different if
you are using a custom subclass of the JdbcTemplate class).
I have a JPA Query I am executing on the Google App-Engine datastore.
I am building the query using parameters.
After all parameters have been inputted, I wish to view the Query String.
That is, I wish to view the actual query being executed by the datastore.
Is that even possible?
It would really help me in debugging.
To SOLVE the question, assume the following query:
Query query=EM.createQuery("SELECT FROM "
+MyClass.class.getName()+" C WHERE C.field = :arg1");
query.setParameter("arg1", someParam);
if System.out.println(SomeObj) prints 'SELECT FROM MyClass C WHERE C.field = 17'
then the question is solved.
David
That is, I wish to view the actual query being executed by the datastore.
Enabling DEBUG for the DataNucleus.Datastore log category should do it. Check the DataNucleus Logging documentation.
In current DataNucleus you can just call toString() on the JPA Query object to see the single-string form (without parameter substitution). The actual query invoked on the datastore depends on the datastore (obviously), being SQL in the case of RDBMS, and something else in the case of BigTable.