在JPA(以及JBoss 5中包含的其余Hibernate软件包)中使用Hibernate 3.3.2GA时出现奇怪的性能问题。
我正在使用本机查询,并将SQL组装为准备好的语句。
EntityManager em = getEntityManager(MY_DS); final Query query = em.createNativeQuery(fullSql, entity.getClass());
SQL有很多联接,但是实际上非常基本,只有一个参数。喜欢:
SELECT field1, field2, field3 FROM entity left join entity2 on... left join entity3 on WHERE stringId like ?
该查询将在一秒钟内在MSSQL Studio上运行。
如果我加
query.setParameter(0, "ABC123%");
查询将暂停9秒
2012-01-20 14:36:21 - TRACE: - AbstractBatcher.getPreparedStatement:(484) | preparing statement 2012-01-20 14:36:21 - TRACE: - StringType.nullSafeSet:(133) | binding 'ABC123%' to parameter: 1 2012-01-20 14:36:30 - DEBUG: - AbstractBatcher.logOpenResults:(382) | about to open ResultSet (open ResultSets: 0, globally: 0)
但是,如果我只替换“?” 值(使其不是Prepared Statement,而只是直接的SQL查询。
fullSql = fullSql.replace("?", "'ABC123%'");
查询将在不到一秒钟的时间内完成。
我真的更希望我们有一个Prepared语句(正在从用户数据中提取参数的输入),以防止注入攻击。
追溯代码中的慢点,我深入到jtds-1.2.2包中。令人讨厌的行似乎是SharedSocket行841“ getIn()。readFully(hdrBuf);” 那里没有什么真正明显的…
private byte[] readPacket(byte buffer[]) throws IOException { // // Read rest of header try { getIn().readFully(hdrBuf); } catch (EOFException e) { throw new IOException("DB server closed connection."); }
通过这个堆栈到达…
at net.sourceforge.jtds.jdbc.SharedSocket.readPacket(SharedSocket.java:841) at net.sourceforge.jtds.jdbc.SharedSocket.getNetPacket(SharedSocket.java:722) at net.sourceforge.jtds.jdbc.ResponseStream.getPacket(ResponseStream.java:466) at net.sourceforge.jtds.jdbc.ResponseStream.read(ResponseStream.java:103) at net.sourceforge.jtds.jdbc.ResponseStream.peek(ResponseStream.java:88) at net.sourceforge.jtds.jdbc.TdsCore.wait(TdsCore.java:3928) at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java:1045) at net.sourceforge.jtds.jdbc.TdsCore.microsoftPrepare(TdsCore.java:1178) at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareSQL(ConnectionJDBC2.java:657) at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java:776) at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208) at org.hibernate.loader.Loader.getResultSet(Loader.java:1808) at org.hibernate.loader.Loader.doQuery(Loader.java:697) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259) at org.hibernate.loader.Loader.doList(Loader.java:2228) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125) at org.hibernate.loader.Loader.list(Loader.java:2120) at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:312) at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1722) at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:165) at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:175) at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:67)
我将保留此问题,并在此处回答,以防将来有人遇到相同的问题。
问题在于JTDS驱动程序将参数字符串发送到MSSQL的方式。显然,Java默认会尝试发送参数Unicode,而MSSQL会将其转换为Ascii。我不知道为什么要花9秒钟。
那里有很多参考资料,但是直到我能够隔离出这是MSSQL连接驱动程序的问题,才无济于事。
该链接很有帮助:
[http://server.pramati.com/blog/2010/06/02/perfissues-jdbcdrivers- mssqlserver/]
这是使用Microsoft驱动程序的字符串。
jdbc:sqlserver://localhost\SQLEXPRESS; DatabaseName=TESTDB; sendStringParametersAsUnicode=false
您只需要将sendStringParametersAsUnicode = false传递给驱动程序URL设置,就可以了。