Does Cassandra DataStax's #Select annotation use PreparedStatements in the generated queries? Is it effective like if I use a PreparedStatement and execute it manually?
Yes, mappers also prepare the statements. If you observe the logs generated out of the mappers, you could see it prepare the statements for us. For e.g. when you configure logging you'll notice things like below when the mapper code is constructed,
DEBUG ProductDaoImpl__MapperGenerated - [s0] Initializing new instance for keyspace = ks_0 and table = null
DEBUG ProductHelper__MapperGenerated - [s0] Entity Product will be mapped to ks_0.product
DEBUG ProductDaoImpl__MapperGenerated - [s0] Preparing query
`SELECT id,description,dimensions FROM ks_0.product WHERE id=:id`
for method findById(java.util.UUID)
Optional / Bonus:
As recommended in the DataStax Java Driver documentation here, you could & should definitely leverage PreparedStatements while working with QueryBuilder favoring bound statements for queries that are used often. You can still use the query builder and prepare the result:
// During application initialization:
Select selectUser = selectFrom("user").all().whereColumn("id").isEqualTo(bindMarker());
// SELECT * FROM user WHERE id=?
PreparedStatement preparedSelectUser = session.prepare(selectUser.build());
// At runtime:
session.execute(preparedSelectUser.bind(userId));
Related
For the purpose of optimizing big insert processes in our system, we intend to batch in our insert sql statements. But no matter what I configure, so far, I'm not able to accomplish that.
Based on the answer on this SO question:
Hibernate batch size confusion
It should be possible.
I already configured the hibernate.jdbc.batch_size property but still was not able to batch the insert statements? I can confirm this by enabling sql logs on both hibernate side and the postgres server side.
Is it possible to merge multiple insert statements to 1 insert statement in hibernate with postgres db?
Sample entity I used below:
class GenericMessage {
String name
//other fields
}
I'm using GORM, so it's on groovy (These are done in a transaction):
GenericMessage message1 = new GenericMessage(name: 'name1').save()
GenericMessage message2 = new GenericMessage(name: 'name2').save()
session.flush()
session.clear()
I have a java application that does a SQL query against an Oracle database, that for some reason gives way less values when executed from the SQL Developer and from the application itself.
Now to the technicalities. The application produces a connection to the db using a wrapper library that employs c3p0. The c3p0 config has been checked, so we know that this things can't be:
-Pointing to wrong database/schema
-Restricted user
Then there's the query:
select to_char(AGEPINDW.TRANSACTION.TS_TRANSACTION,'yyyy-mm') as Time,result, count(*) as TOTAL, sum(face_value) as TOTAL_AMOUNT
from AGEPINDW.TRANSACTION
where (ts_transaction >= to_timestamp(to_char(add_months(sysdate,-1),'yyyy-mm'),'yyyy-mm')
and ts_transaction < to_timestamp(to_char(sysdate,'yyyy-mm'),'yyyy-mm')) and service_id in (2,23)
group by to_char(AGEPINDW.TRANSACTION.TS_TRANSACTION,'yyyy-mm'), result;
It doesn't have any parameter and is executed via your standard PreparedStatement. Yet the return from the app is wrong and I don't know what may be. Any suggestions?
I'm looking for an utility to run a JPA query and display the query along with its results in console. Just like running a select statement in native sql client:
ij> select * from standalonejpa.Emp_PHONE;
EMPLOYEE_ID|PHONE_NUM |PHONENUMBE&
--------------------------------------------
1 |12938302 |0
I would like to write a method that would accept one parameter - table name - and produce above statement to console by running EntityManager's createQuery() and getResultList(). Do you know such utility or I have to carefully craft it myself?
Not sure about a utility, but you can enable logging to show the resulting SQL.
As for crafting one, I would create a listener that interfaces with EclipseLink's logger to capture the log output then display it on the screen.
You can send JPA queries directly through the persistence layer, the only thing you can't do (or can't do easily) at runtime is adding new classes as the JPA enabled classes have to be known at startup. Though there should be an implementation specific way to register new JPA classes at runtime.
I ended up with the solution that uses JDBC query and pretty print the results with Derbytools utility class. I'm selecting all tables from the JPA project like that:
Connection conn = em.unwrap(Connection.class);
Statement st = conn.createStatement();
for(EntityType<?> et : emf.getMetamodel().getEntities()) {
String query = "SELECT * FROM " + et.getName();
System.out.println("> " + query);
st.execute(query);
JDBCDisplayUtil.DisplayResults(System.out, st, conn);
}
As a result I have pretty formatted results like:
> SELECT * FROM Employee
ID
-----------
1
51
Here comes the information to keep completeness of this post:
I used EclipseLink java.sql.Connection unwrapping and added to my pom.xml dependency to Derbytools:
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbytools</artifactId>
<version>10.10.2.0</version>
</dependency>
Actually you can use pretty-printing from Derbytools with any database, not only Apache Derby.
The whole hassle I make was to create a "testing" project for JPA mappings, that will be displaying generated tables along with data in there. The whole project is called "jpa-testing" and it is available from my github.
Came across some code today that uses Hibernate to perform a query. The query uses a value submitted from a form. It made me curious as to whether or not this sort of code "sanitizes" its input.
public List<School> search(String query) {
Session session = this.getCurrentSession();
query = "%" + query + "%";
Criteria criteria = session.createCriteria(getPersistentClass());
criteria.createAlias("country", "a");
Criterion nameCriterion = Restrictions.ilike("name", query);
Criterion cityCriterion = Restrictions.ilike("city", query);
Criterion countryCriterion = Restrictions.ilike("a.name", query);
Criterion criterion = Restrictions.or(Restrictions.or(nameCriterion, cityCriterion), countryCriterion);
criteria.add(criterion);
return criteria.list();
}
Is this safe?
Hibernate Criteria Queries are quiet safe in terms of Sql Injection since they pass strings as parameter while performing any fetch. Even, Hql is quiet safe unless you build the query via string literal.
For more details, you should take a look at queries getting fired at the database level by switching on hibernate sql logging.
If you think to SQL injection attacks, then yes, Hibernate Criteria API is safe.
It will generate the underlying query by first compiling it from the specified query fields and only after apply the query parameters (It should use a classical PreparedStatement). This way the JDBC driver will know which part of the query are fields and which part are parameters. Then the driver will take care to sanitize the parameters.
Tough you should take care with the SQL restrictions applied on the Criteria, if you need to place parameters there. For example
String vulnerable = //parameter from user interface
criteria.add(
Restrictions.sqlRestriction("some sql like + vulnerable") //vulnerable
criteria.add(
Restrictions.sqlRestriction("some sql like ?",
vulnerable, Hibernate.STRING)) //safe
In this case the vulnerable parameter could "leak" in to the query fields part and be bypassed by JDBC driver checking as in a normal vulnerable SQL query.
Hibernate is useful to sanitizing inputs but sanitizing inputs is not considered the best practice for preventing SQL injection attacks. As your code develops over time, you will need to remember to change your Hibernate sanitation as your database and client-side application change; this leaves a lot of room for error and any one mistake can compromise your database.
To prevent SQL injection attacks, it is better to use prepared statements. In a prepared statement, your client-side application will make a non-SQL request and let your server generate your SQL statement.
For example, if a user wants all users in the city "Dallas" then your client-side application should make a request similar to username equals "Dallas" and then your server can generate:
SELECT * FROM users WHERE name='Dallas'
I have the following hibernate query:
Query query = session.createQuery("from MyHibernateClass");
List<MyHibernateClass> result = query.list();// executes in 7000ms
When logging the sql being executed in MySQL I see
select
myhibernat0_.myFirstColumn as myfirstcolumn92_,
myhibernat0_.mySecondColumn as mysecondcolumn92_,
myhibernat0_.mythirdcolumn as mythirdcolumn92_,
myhibernat0_.myFourthColumn as myfourthcolumn92_
from MyHibernateClass myhibernat0_
where (1=1);
When measurering the java code in the jvm on a small dataset of 3500 rows in MyHibernateClass database table this takes about 7000ms.
If I on the otherhand uses direct jdbc as follows:
Statement statement = session.connection().createStatement();
ResultSet rs = statement.executeQuery("select * from MyHibernateClass");// 7ms
List<MyHibernateClass> result = convert(rs);// executes in 20ms
I see the same sql going into the database but now the time spend in the java code in the jvm is 7ms.
The MyHibernateClass is a simple java bean class with getters and setters, I use no special resulttransformers as can be seen in the example. I only need a read-only instance of the class, and it doesn't need to be attached to the hibernate session.
I would rather like to use the hibernate version but cannot accept the execution times.
Added information:
After adding hibernate logging I see
[2011-07-07 14:26:26,643]DEBUG [main] [logid: ] -
org.hibernate.jdbc.AbstractBatcher.logOpenResults(AbstractBatcher.java:426) -
about to open ResultSet (open ResultSets: 0, globally: 0)
followed by 3500 of the following log statements
[2011-07-07 14:26:26,649]DEBUG [main] [logid: ] -
org.hibernate.loader.Loader.getRow(Loader.java:1197) -
result row: EntityKey[com.mycom.MyHibernateClass#1]
followed by 3500 log statements like
[2011-07-07 14:27:06,789]DEBUG [main] [logid: ] -
org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:130) -
resolving associations for [com.mycom.MyHibernateClass#1]
[2011-07-07 14:27:06,792]DEBUG [main] [logid: ] -
org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:226) -
done materializing entity [com.mycom.MyHibernateClass#1]
What does this mean?
What is Hibernate doing in the first implementation, how can I find out?
Adding a constructor with all attributes of the class did the trick, now the execution times are 70ms for the hibernate query. Previously the class only had a default constructor without arguments and a constructor with the entity id argument.
Based on the new information I felt I should provide another answer. The difference looks like that you have a one-to-many association specified for a List or Set property in your bean.
You are probably specifying that lazy=false which will turn off lazy loading. With lazy loading turned off it will fetch every associated record for every MyHibernateClass entity and this is why it is taking so long to execute.
Try setting lazy=true and this will perform much faster and then only retrieve the associated entities when explicitly requesting them from the entity.
If you utilize Log4j in your application you can set a variety of different logging options specific to Hibernate to get a better picture of what is going on behind the scenes in Hibernate.
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuration.html#configuration-logging
My guess is that this is the typical initial load time that occurs when first calling an HQL query in an application. Subsequent HQL queries should be noticeably and considerably faster after this first one.
I know this thread is old, but to update I ran into the same problem but with SQL Server and it turns out to be that SQL being printed by Hibernate and SQL Sent using the driver is different. Using MSSQL Driver by default sends the queries as stored procedures as RPC calls it's because the driver tries to optimize the query plan for MSSQL Standards , so it sends the queries something like
Hibernate Query:
select c.col1,c.col2 from customer c where c.name like #param1 and c.country like #param2
Actual Driver Sent Query:
#param1=somevalue, #param2=somevalue
declar sp ....
select c.col1,c.col2 from customer c where c.name like #param1 and c.country like #param2
go
Note: This Query I got through SQL Profiler Tool directly listening on DB
It turns out to be that sp_exec optimizations on the MSSQL tend to produce good Query plans that's get cached, but this would result in 'parameter sniffing' to know more about this problem read here...
So to overcome this I had following options:
Change my HQL to native Queries and add OPTION RECOMPILE FOR SOME PARAM
Use Direct query values instead of prepared statements so there will be no translation for param values and queries will not be modified as Stored Procedures by the Driver
Change the driver settings to not send the stored procedures (this is still bad because now the query plans in MSSQL server will be specific to this query, this is same as Option:2 but outside the code)
I didn't want to use OPTION 1 & 2 since that eliminates the whole purpose of using ORM Frameworks and I end up using OPTION 3 for now
So I changed the JDBC URL to send option prepareStatement=false
After setting this I had one more problem the query being sent like
Select * from customer c where c.name like **N**'somename' and c.country=**N**'somevalue'
Here there is a prefix before the values which states that to convert the encoding scheme , so I disable the JDBC url to sendUnicode = false
This all I did in JTDS driver options.. As far as I am concerned now the application is up and running fast. I have also introduced second level caches to cache it for some time..
Hope this helps for someone, if you have any good suggestion please let me know.
I had an incident where my application was always using every row in the result set of a query. I found a 40-fold increase in speed by setting my fetch size using the setFetchSize method below. (The performance improvement includes the addition of the count query.)
Long count = getStoreCount(customerId);
Query query = session.getNamedQuery("hqlGetStoresByCustomerId")
.setString("i_customerid",customerId)
.setFetchSize(count.intValue());
Be careful while doing this; my data set had about 100 rows, and it was scoped to a the life of a web request. If you have larger data sets, you will be eating Java Heap for the duration of the existence of that data, prior to returning it to the Java Heap.
I know this is an old question but here is what fixed it for me...
In your hibernate.cfg.xml make sure you have the correct !DOCTYPE... it should be as follows:
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
Anyone else who is facing a similar issue with SQL Server can use sendStringParametersAsUnicode=false in the JDBC Query String as shown in this answer:
JPA (Hibernate) Native Query for Prepared Statement SLOW
If you're not using Unicode for your prepared statement parameters and want to utilize the index on the varchar field which you're using as a parameter for the prepared statement, this can help.
It took me 10 seconds to execute a simple select all query before I found out that DOCTYPE tag is written wrongly in hibernate.cfg.xml and *mapping object*.hbm.class
Make sure that hibernate.cfg.xml start with
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
And mapping xml.class with
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
Now it took me 1-2 seconds to execute any queries.