当前位置: 首页 > 面试题库 >

JPA(休眠)本机查询,用于准备好的语句SLOW

燕成双
2023-03-14
问题内容

在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设置,就可以了。



 类似资料:
  • 问题内容: 在将HQL转换为SQL时,Hibernate在JDBC内部使用PreparedStatement。HQL中的内联参数如何处理? 例: 将状态“解析”并用作SQL中的参数,或者将其作为内联参数发送。 我的观点背后的原因是“最佳做法”,以及针对重复调用的查询性能 问题答案: 它被内联发送。当是客户端控制的值时,您绝对不希望这样做。 而是将其参数化: 也可以看看: OWASP-hiberna

  • 问题内容: 我们正在将JPA与hibernate用作提供程序,我们有一个查询,该查询包含一个与FROM子句中的子查询的联接,但是会出现以下错误: org.hibernate.hql.ast.QuerySyntaxException:意外令牌:(在第1行第75列附近[SELECT sd from com.hp.amber.datamodel.entities.analysis.SnapshotDat

  • 我有一个类,其中我使用旧的jdbc方法创建了到h2数据库的连接,该方法编写url并获取连接,我在数据库中创建了一个表,这个表不是java对象,所以我用尽了聪明的方法来为我的方法编写测试 //我还创建了一个表app_user公共void addUser(连接连接,字符串登录,字符串密码,字符串描述)抛出SQLException{ 而我的测试方法看起来像这样,有没有办法让它不那么整洁,更简单,我试图用

  • 问题内容: 我想按数据库中的条件计数记录数。 我尝试使用下一个查询 但是没有方法可以执行此操作并获得结果。 我知道,我可以使用 所以问题是,查询是否具有更高的性能?如果,那么如何执行查询呢? 问题答案: 您可以通过调用来执行第一个查询,例如。 如果要将计数分配给变量,则需要将其转换为适当的类型(它可以取决于DB,但很可能是Long)。第二个查询效率很低,因为Hibernate需要从数据库中检索整个

  • 问题内容: 我想使用Hibernate从文件运行本机SQL。SQL可以包含创建数据库结构的多个语句(即表,约束,但没有insert / update / delete语句)。 示例,下面是一个非常简单的查询(包含以下两个SQL语句) 我正在使用MySQL数据库,当我运行上述查询时,我返回了gettng语法错误。当我一一运行它们时,就可以了。 下面是运行查询的代码(上面的语句已分配给“ sql”变量